/* ----------------------------------------------------------------------- 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 <ffi_cfi.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): cfi_startproc 1: iflush %o0 iflush %o+8 nop nop nop nop nop retl nop cfi_endproc .size C(ffi_flush_icache), . - C(ffi_flush_icache) #endif .macro E index .align 16 .org 2b + \index * 16 .endm .align 8 .globl C(ffi_call_v8) .type C(ffi_call_v8),@function FFI_HIDDEN(C(ffi_call_v8)) C(ffi_call_v8): cfi_startproc ! Allocate a stack frame sized by ffi_call. save %sp, %o4, %sp cfi_def_cfa_register(%fp) cfi_window_save 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 10f srl %o0, 8, %o0 E SPARC_RET_F_1 st %f0, [%i2] ret restore .align 8 9: sth %o0, [%i2] ret restore .align 8 10: 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 = 0b + size*20 jmp %o7+(2f-8b) mov %i5, %g2 ! load static chain 2: .rept 0x1000 call %i1 nop unimp (. - 2b) / 20 ret restore .endr cfi_endproc .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): cfi_startproc save %sp, -STACKFRAME, %sp cfi_def_cfa_register(%fp) cfi_window_save ld [%g2+4], %o0 ! load cif ld [%g2+8], %o1 ! load fun b 0f mov %g2, %o2 ! load user_data cfi_endproc .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): cfi_startproc save %sp, -STACKFRAME, %sp cfi_def_cfa_register(%fp) cfi_window_save 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 cfi_endproc .size C(ffi_closure_v8), . - C(ffi_closure_v8) #endif /* !SPARC64 */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif