| /* ----------------------------------------------------------------------- |
| v8.S - Copyright (c) 2013 The Written Word, Inc. |
| Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. |
| |
| SPARC Foreign Function Interface |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| ``Software''), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be included |
| in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL 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 "internal.h" |
| |
| #ifndef SPARC64 |
| |
| #define C2(X, Y) X ## Y |
| #define C1(X, Y) C2(X, Y) |
| |
| #ifdef __USER_LABEL_PREFIX__ |
| # define C(Y) C1(__USER_LABEL_PREFIX__, Y) |
| #else |
| # define C(Y) Y |
| #endif |
| #define L(Y) C1(.L, Y) |
| |
| .text |
| |
| #ifndef __GNUC__ |
| .align 8 |
| .globl C(ffi_flush_icache) |
| .type C(ffi_flush_icache),#function |
| FFI_HIDDEN(C(ffi_flush_icache)) |
| |
| C(ffi_flush_icache): |
| 1: iflush %o0 |
| iflush %o+8 |
| nop |
| nop |
| nop |
| nop |
| nop |
| retl |
| nop |
| .size C(ffi_flush_icache), . - C(ffi_flush_icache) |
| #endif |
| |
| #if defined(__sun__) && defined(__svr4__) |
| # define E(INDEX) .align 16 |
| #else |
| # define E(INDEX) .align 16; .org 2b + INDEX * 16 |
| #endif |
| |
| .align 8 |
| .globl C(ffi_call_v8) |
| .type C(ffi_call_v8),#function |
| FFI_HIDDEN(C(ffi_call_v8)) |
| |
| C(ffi_call_v8): |
| .LUW0: |
| ! Allocate a stack frame sized by ffi_call. |
| save %sp, %o4, %sp |
| .LUW1: |
| mov %i0, %o0 ! copy cif |
| add %sp, 64+32, %o1 ! load args area |
| mov %i2, %o2 ! copy rvalue |
| call C(ffi_prep_args_v8) |
| mov %i3, %o3 ! copy avalue |
| |
| add %sp, 32, %sp ! deallocate prep frame |
| and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type |
| srl %o0, SPARC_SIZEMASK_SHIFT, %l1 ! save return size |
| ld [%sp+64+4], %o0 ! load all argument registers |
| ld [%sp+64+8], %o1 |
| ld [%sp+64+12], %o2 |
| ld [%sp+64+16], %o3 |
| cmp %l0, SPARC_RET_STRUCT ! struct return needs an unimp 4 |
| ld [%sp+64+20], %o4 |
| be 8f |
| ld [%sp+64+24], %o5 |
| |
| ! Call foreign function |
| call %i1 |
| mov %i5, %g2 ! load static chain |
| |
| 0: call 1f ! load pc in %o7 |
| sll %l0, 4, %l0 |
| 1: add %o7, %l0, %o7 ! o7 = 0b + ret_type*16 |
| jmp %o7+(2f-0b) |
| nop |
| |
| ! Note that each entry is 4 insns, enforced by the E macro. |
| .align 16 |
| 2: |
| E(SPARC_RET_VOID) |
| ret |
| restore |
| E(SPARC_RET_STRUCT) |
| unimp |
| E(SPARC_RET_UINT8) |
| and %o0, 0xff, %o0 |
| st %o0, [%i2] |
| ret |
| restore |
| E(SPARC_RET_SINT8) |
| sll %o0, 24, %o0 |
| b 7f |
| sra %o0, 24, %o0 |
| E(SPARC_RET_UINT16) |
| sll %o0, 16, %o0 |
| b 7f |
| srl %o0, 16, %o0 |
| E(SPARC_RET_SINT16) |
| sll %o0, 16, %o0 |
| b 7f |
| sra %o0, 16, %o0 |
| E(SPARC_RET_UINT32) |
| 7: st %o0, [%i2] |
| ret |
| restore |
| E(SP_V8_RET_CPLX16) |
| sth %o0, [%i2+2] |
| b 9f |
| srl %o0, 16, %o0 |
| E(SPARC_RET_INT64) |
| st %o0, [%i2] |
| st %o1, [%i2+4] |
| ret |
| restore |
| E(SPARC_RET_INT128) |
| std %o0, [%i2] |
| std %o2, [%i2+8] |
| ret |
| restore |
| E(SPARC_RET_F_8) |
| st %f7, [%i2+7*4] |
| nop |
| st %f6, [%i2+6*4] |
| nop |
| E(SPARC_RET_F_6) |
| st %f5, [%i2+5*4] |
| nop |
| st %f4, [%i2+4*4] |
| nop |
| E(SPARC_RET_F_4) |
| st %f3, [%i2+3*4] |
| nop |
| st %f2, [%i2+2*4] |
| nop |
| E(SPARC_RET_F_2) |
| st %f1, [%i2+4] |
| st %f0, [%i2] |
| ret |
| restore |
| E(SP_V8_RET_CPLX8) |
| stb %o0, [%i2+1] |
| b 0f |
| srl %o0, 8, %o0 |
| E(SPARC_RET_F_1) |
| st %f0, [%i2] |
| ret |
| restore |
| |
| .align 8 |
| 9: sth %o0, [%i2] |
| ret |
| restore |
| .align 8 |
| 0: stb %o0, [%i2] |
| ret |
| restore |
| |
| ! Struct returning functions expect and skip the unimp here. |
| ! To make it worse, conforming callees examine the unimp and |
| ! make sure the low 12 bits of the unimp match the size of |
| ! the struct being returned. |
| .align 8 |
| 8: call 1f ! load pc in %o7 |
| sll %l1, 2, %l0 ! size * 4 |
| 1: sll %l1, 4, %l1 ! size * 16 |
| add %l0, %l1, %l0 ! size * 20 |
| add %o7, %l0, %o7 ! o7 = 8b + size*20 |
| jmp %o7+(2f-8b) |
| mov %i5, %g2 ! load static chain |
| 2: |
| |
| /* The Sun assembler doesn't understand .rept 0x1000. */ |
| #define rept1 \ |
| call %i1; \ |
| nop; \ |
| unimp (. - 2b) / 20; \ |
| ret; \ |
| restore |
| |
| #define rept16 \ |
| rept1; rept1; rept1; rept1; \ |
| rept1; rept1; rept1; rept1; \ |
| rept1; rept1; rept1; rept1; \ |
| rept1; rept1; rept1; rept1 |
| |
| #define rept256 \ |
| rept16; rept16; rept16; rept16; \ |
| rept16; rept16; rept16; rept16; \ |
| rept16; rept16; rept16; rept16; \ |
| rept16; rept16; rept16; rept16 |
| |
| rept256; rept256; rept256; rept256 |
| rept256; rept256; rept256; rept256 |
| rept256; rept256; rept256; rept256 |
| rept256; rept256; rept256; rept256 |
| |
| .LUW2: |
| .size C(ffi_call_v8),. - C(ffi_call_v8) |
| |
| |
| /* 16*4 register window + 1*4 struct return + 6*4 args backing store |
| + 8*4 return storage + 1*4 alignment. */ |
| #define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4) |
| |
| /* ffi_closure_v8(...) |
| |
| Receives the closure argument in %g2. */ |
| |
| #ifdef HAVE_AS_REGISTER_PSEUDO_OP |
| .register %g2, #scratch |
| #endif |
| |
| .align 8 |
| .globl C(ffi_go_closure_v8) |
| .type C(ffi_go_closure_v8),#function |
| FFI_HIDDEN(C(ffi_go_closure_v8)) |
| |
| C(ffi_go_closure_v8): |
| .LUW3: |
| save %sp, -STACKFRAME, %sp |
| .LUW4: |
| ld [%g2+4], %o0 ! load cif |
| ld [%g2+8], %o1 ! load fun |
| b 0f |
| mov %g2, %o2 ! load user_data |
| .LUW5: |
| .size C(ffi_go_closure_v8), . - C(ffi_go_closure_v8) |
| |
| .align 8 |
| .globl C(ffi_closure_v8) |
| .type C(ffi_closure_v8),#function |
| FFI_HIDDEN(C(ffi_closure_v8)) |
| |
| C(ffi_closure_v8): |
| .LUW6: |
| save %sp, -STACKFRAME, %sp |
| .LUW7: |
| ld [%g2+FFI_TRAMPOLINE_SIZE], %o0 ! load cif |
| ld [%g2+FFI_TRAMPOLINE_SIZE+4], %o1 ! load fun |
| ld [%g2+FFI_TRAMPOLINE_SIZE+8], %o2 ! load user_data |
| 0: |
| ! Store all of the potential argument registers in va_list format. |
| st %i0, [%fp+68+0] |
| st %i1, [%fp+68+4] |
| st %i2, [%fp+68+8] |
| st %i3, [%fp+68+12] |
| st %i4, [%fp+68+16] |
| st %i5, [%fp+68+20] |
| |
| ! Call ffi_closure_sparc_inner to do the bulk of the work. |
| add %fp, -8*4, %o3 |
| call ffi_closure_sparc_inner_v8 |
| add %fp, 64, %o4 |
| |
| 0: call 1f |
| and %o0, SPARC_FLAG_RET_MASK, %o0 |
| 1: sll %o0, 4, %o0 ! o0 = o0 * 16 |
| add %o7, %o0, %o7 ! o7 = 0b + o0*16 |
| jmp %o7+(2f-0b) |
| add %fp, -8*4, %i2 |
| |
| ! Note that each entry is 4 insns, enforced by the E macro. |
| .align 16 |
| 2: |
| E(SPARC_RET_VOID) |
| ret |
| restore |
| E(SPARC_RET_STRUCT) |
| ld [%i2], %i0 |
| jmp %i7+12 |
| restore |
| E(SPARC_RET_UINT8) |
| ldub [%i2+3], %i0 |
| ret |
| restore |
| E(SPARC_RET_SINT8) |
| ldsb [%i2+3], %i0 |
| ret |
| restore |
| E(SPARC_RET_UINT16) |
| lduh [%i2+2], %i0 |
| ret |
| restore |
| E(SPARC_RET_SINT16) |
| ldsh [%i2+2], %i0 |
| ret |
| restore |
| E(SPARC_RET_UINT32) |
| ld [%i2], %i0 |
| ret |
| restore |
| E(SP_V8_RET_CPLX16) |
| ld [%i2], %i0 |
| ret |
| restore |
| E(SPARC_RET_INT64) |
| ldd [%i2], %i0 |
| ret |
| restore |
| E(SPARC_RET_INT128) |
| ldd [%i2], %i0 |
| ldd [%i2+8], %i2 |
| ret |
| restore |
| E(SPARC_RET_F_8) |
| ld [%i2+7*4], %f7 |
| nop |
| ld [%i2+6*4], %f6 |
| nop |
| E(SPARC_RET_F_6) |
| ld [%i2+5*4], %f5 |
| nop |
| ld [%i2+4*4], %f4 |
| nop |
| E(SPARC_RET_F_4) |
| ld [%i2+3*4], %f3 |
| nop |
| ld [%i2+2*4], %f2 |
| nop |
| E(SPARC_RET_F_2) |
| ldd [%i2], %f0 |
| ret |
| restore |
| E(SP_V8_RET_CPLX8) |
| lduh [%i2], %i0 |
| ret |
| restore |
| E(SPARC_RET_F_1) |
| ld [%i2], %f0 |
| ret |
| restore |
| |
| .LUW8: |
| .size C(ffi_closure_v8), . - C(ffi_closure_v8) |
| |
| #ifdef HAVE_RO_EH_FRAME |
| .section ".eh_frame",#alloc |
| #else |
| .section ".eh_frame",#alloc,#write |
| #endif |
| |
| #ifdef HAVE_AS_SPARC_UA_PCREL |
| # define FDE_ADDR(X) %r_disp32(X) |
| #else |
| # define FDE_ADDR(X) X |
| #endif |
| |
| .align 4 |
| .LCIE: |
| .long .LECIE - .LSCIE ! CIE Length |
| .LSCIE: |
| .long 0 ! CIE Identifier Tag |
| .byte 1 ! CIE Version |
| .ascii "zR\0" ! CIE Augmentation |
| .byte 4 ! CIE Code Alignment Factor |
| .byte 0x7c ! CIE Data Alignment Factor |
| .byte 15 ! CIE RA Column |
| .byte 1 ! Augmentation size |
| #ifdef HAVE_AS_SPARC_UA_PCREL |
| .byte 0x1b ! FDE Encoding (pcrel sdata4) |
| #else |
| .byte 0x50 ! FDE Encoding (aligned absolute) |
| #endif |
| .byte 0xc, 14, 0 ! DW_CFA_def_cfa, %o6, offset 0 |
| .align 4 |
| .LECIE: |
| |
| .long .LEFDE1 - .LSFDE1 ! FDE Length |
| .LSFDE1: |
| .long .LSFDE1 - .LCIE ! FDE CIE offset |
| .long FDE_ADDR(.LUW0) ! Initial location |
| .long .LUW2 - .LUW0 ! Address range |
| .byte 0 ! Augmentation size |
| .byte 0x40+1 ! DW_CFA_advance_loc 4 |
| .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6 |
| .byte 0x2d ! DW_CFA_GNU_window_save |
| .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7 |
| .align 4 |
| .LEFDE1: |
| |
| .long .LEFDE2 - .LSFDE2 ! FDE Length |
| .LSFDE2: |
| .long .LSFDE2 - .LCIE ! FDE CIE offset |
| .long FDE_ADDR(.LUW3) ! Initial location |
| .long .LUW5 - .LUW3 ! Address range |
| .byte 0 ! Augmentation size |
| .byte 0x40+1 ! DW_CFA_advance_loc 4 |
| .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6 |
| .byte 0x2d ! DW_CFA_GNU_window_save |
| .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7 |
| .align 4 |
| .LEFDE2: |
| |
| .long .LEFDE3 - .LSFDE3 ! FDE Length |
| .LSFDE3: |
| .long .LSFDE3 - .LCIE ! FDE CIE offset |
| .long FDE_ADDR(.LUW6) ! Initial location |
| .long .LUW8 - .LUW6 ! Address range |
| .byte 0 ! Augmentation size |
| .byte 0x40+1 ! DW_CFA_advance_loc 4 |
| .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6 |
| .byte 0x2d ! DW_CFA_GNU_window_save |
| .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7 |
| .align 4 |
| .LEFDE3: |
| |
| #endif /* !SPARC64 */ |
| #if defined __ELF__ && defined __linux__ |
| .section .note.GNU-stack,"",@progbits |
| #endif |