| /* ----------------------------------------------------------------------- |
| sysv.S - Copyright (c) 2003, 2004, 2006, 2008 Kaz Kojima |
| |
| SuperH SHmedia 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> |
| #ifdef HAVE_MACHINE_ASM_H |
| #include <machine/asm.h> |
| #else |
| /* XXX these lose for some platforms, I'm sure. */ |
| #define CNAME(x) x |
| #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): |
| #endif |
| |
| #ifdef __LITTLE_ENDIAN__ |
| #define OFS_FLT 0 |
| #else |
| #define OFS_FLT 4 |
| #endif |
| |
| .section .text..SHmedia32,"ax" |
| |
| # r2: ffi_prep_args |
| # r3: &ecif |
| # r4: bytes |
| # r5: flags |
| # r6: flags2 |
| # r7: rvalue |
| # r8: fn |
| |
| # This assumes we are using gas. |
| .align 5 |
| ENTRY(ffi_call_SYSV) |
| # Save registers |
| .LFB1: |
| addi.l r15, -48, r15 |
| .LCFI0: |
| st.q r15, 40, r32 |
| st.q r15, 32, r31 |
| st.q r15, 24, r30 |
| st.q r15, 16, r29 |
| st.q r15, 8, r28 |
| st.l r15, 4, r18 |
| st.l r15, 0, r14 |
| .LCFI1: |
| add.l r15, r63, r14 |
| .LCFI2: |
| # add r4, r63, r28 |
| add r5, r63, r29 |
| add r6, r63, r30 |
| add r7, r63, r31 |
| add r8, r63, r32 |
| |
| addi r4, (64 + 7), r4 |
| andi r4, ~7, r4 |
| sub.l r15, r4, r15 |
| |
| ptabs/l r2, tr0 |
| add r15, r63, r2 |
| blink tr0, r18 |
| |
| addi r15, 64, r22 |
| movi 0, r0 |
| movi 0, r1 |
| movi -1, r23 |
| |
| pt/l 1f, tr1 |
| bnei/l r29, FFI_TYPE_STRUCT, tr1 |
| ld.l r15, 0, r19 |
| addi r15, 8, r15 |
| addi r0, 1, r0 |
| 1: |
| |
| .L_pass: |
| andi r30, 3, r20 |
| shlri r30, 2, r30 |
| |
| pt/l .L_call_it, tr0 |
| pt/l .L_pass_i, tr1 |
| pt/l .L_pass_f, tr2 |
| |
| beqi/l r20, FFI_TYPE_VOID, tr0 |
| beqi/l r20, FFI_TYPE_INT, tr1 |
| beqi/l r20, FFI_TYPE_FLOAT, tr2 |
| |
| .L_pass_d: |
| addi r0, 1, r0 |
| pt/l 3f, tr0 |
| movi 12, r20 |
| bge/l r1, r20, tr0 |
| |
| pt/l .L_pop_d, tr1 |
| pt/l 2f, tr0 |
| blink tr1, r63 |
| 2: |
| addi.l r15, 8, r15 |
| 3: |
| pt/l .L_pass, tr0 |
| addi r1, 2, r1 |
| blink tr0, r63 |
| |
| .L_pop_d: |
| pt/l .L_pop_d_tbl, tr1 |
| gettr tr1, r20 |
| shlli r1, 2, r21 |
| add r20, r21, r20 |
| ptabs/l r20, tr1 |
| blink tr1, r63 |
| |
| .L_pop_d_tbl: |
| fld.d r15, 0, dr0 |
| blink tr0, r63 |
| fld.d r15, 0, dr2 |
| blink tr0, r63 |
| fld.d r15, 0, dr4 |
| blink tr0, r63 |
| fld.d r15, 0, dr6 |
| blink tr0, r63 |
| fld.d r15, 0, dr8 |
| blink tr0, r63 |
| fld.d r15, 0, dr10 |
| blink tr0, r63 |
| |
| .L_pass_f: |
| addi r0, 1, r0 |
| pt/l 3f, tr0 |
| movi 12, r20 |
| bge/l r1, r20, tr0 |
| |
| pt/l .L_pop_f, tr1 |
| pt/l 2f, tr0 |
| blink tr1, r63 |
| 2: |
| addi.l r15, 8, r15 |
| 3: |
| pt/l .L_pass, tr0 |
| blink tr0, r63 |
| |
| .L_pop_f: |
| pt/l .L_pop_f_tbl, tr1 |
| pt/l 5f, tr2 |
| gettr tr1, r20 |
| bge/l r23, r63, tr2 |
| add r1, r63, r23 |
| shlli r1, 3, r21 |
| addi r1, 2, r1 |
| add r20, r21, r20 |
| ptabs/l r20, tr1 |
| blink tr1, r63 |
| 5: |
| addi r23, 1, r21 |
| movi -1, r23 |
| shlli r21, 3, r21 |
| add r20, r21, r20 |
| ptabs/l r20, tr1 |
| blink tr1, r63 |
| |
| .L_pop_f_tbl: |
| fld.s r15, OFS_FLT, fr0 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr1 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr2 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr3 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr4 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr5 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr6 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr7 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr8 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr9 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr10 |
| blink tr0, r63 |
| fld.s r15, OFS_FLT, fr11 |
| blink tr0, r63 |
| |
| .L_pass_i: |
| pt/l 3f, tr0 |
| movi 8, r20 |
| bge/l r0, r20, tr0 |
| |
| pt/l .L_pop_i, tr1 |
| pt/l 2f, tr0 |
| blink tr1, r63 |
| 2: |
| addi.l r15, 8, r15 |
| 3: |
| pt/l .L_pass, tr0 |
| addi r0, 1, r0 |
| blink tr0, r63 |
| |
| .L_pop_i: |
| pt/l .L_pop_i_tbl, tr1 |
| gettr tr1, r20 |
| shlli r0, 3, r21 |
| add r20, r21, r20 |
| ptabs/l r20, tr1 |
| blink tr1, r63 |
| |
| .L_pop_i_tbl: |
| ld.q r15, 0, r2 |
| blink tr0, r63 |
| ld.q r15, 0, r3 |
| blink tr0, r63 |
| ld.q r15, 0, r4 |
| blink tr0, r63 |
| ld.q r15, 0, r5 |
| blink tr0, r63 |
| ld.q r15, 0, r6 |
| blink tr0, r63 |
| ld.q r15, 0, r7 |
| blink tr0, r63 |
| ld.q r15, 0, r8 |
| blink tr0, r63 |
| ld.q r15, 0, r9 |
| blink tr0, r63 |
| |
| .L_call_it: |
| # call function |
| pt/l 1f, tr1 |
| bnei/l r29, FFI_TYPE_STRUCT, tr1 |
| add r19, r63, r2 |
| 1: |
| add r22, r63, r15 |
| ptabs/l r32, tr0 |
| blink tr0, r18 |
| |
| pt/l .L_ret_i, tr0 |
| pt/l .L_ret_ll, tr1 |
| pt/l .L_ret_d, tr2 |
| pt/l .L_ret_f, tr3 |
| pt/l .L_epilogue, tr4 |
| |
| beqi/l r29, FFI_TYPE_INT, tr0 |
| beqi/l r29, FFI_TYPE_UINT32, tr0 |
| beqi/l r29, FFI_TYPE_SINT64, tr1 |
| beqi/l r29, FFI_TYPE_UINT64, tr1 |
| beqi/l r29, FFI_TYPE_DOUBLE, tr2 |
| beqi/l r29, FFI_TYPE_FLOAT, tr3 |
| |
| pt/l .L_ret_q, tr0 |
| pt/l .L_ret_h, tr1 |
| |
| beqi/l r29, FFI_TYPE_UINT8, tr0 |
| beqi/l r29, FFI_TYPE_UINT16, tr1 |
| blink tr4, r63 |
| |
| .L_ret_d: |
| fst.d r31, 0, dr0 |
| blink tr4, r63 |
| |
| .L_ret_ll: |
| st.q r31, 0, r2 |
| blink tr4, r63 |
| |
| .L_ret_f: |
| fst.s r31, OFS_FLT, fr0 |
| blink tr4, r63 |
| |
| .L_ret_q: |
| st.b r31, 0, r2 |
| blink tr4, r63 |
| |
| .L_ret_h: |
| st.w r31, 0, r2 |
| blink tr4, r63 |
| |
| .L_ret_i: |
| st.l r31, 0, r2 |
| # Fall |
| |
| .L_epilogue: |
| # Remove the space we pushed for the args |
| add r14, r63, r15 |
| |
| ld.l r15, 0, r14 |
| ld.l r15, 4, r18 |
| ld.q r15, 8, r28 |
| ld.q r15, 16, r29 |
| ld.q r15, 24, r30 |
| ld.q r15, 32, r31 |
| ld.q r15, 40, r32 |
| addi.l r15, 48, r15 |
| ptabs r18, tr0 |
| blink tr0, r63 |
| |
| .LFE1: |
| .ffi_call_SYSV_end: |
| .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) |
| |
| .align 5 |
| ENTRY(ffi_closure_SYSV) |
| .LFB2: |
| addi.l r15, -136, r15 |
| .LCFI3: |
| st.l r15, 12, r18 |
| st.l r15, 8, r14 |
| st.l r15, 4, r12 |
| .LCFI4: |
| add r15, r63, r14 |
| .LCFI5: |
| /* Stack layout: |
| ... |
| 64 bytes (register parameters) |
| 48 bytes (floating register parameters) |
| 8 bytes (result) |
| 4 bytes (r18) |
| 4 bytes (r14) |
| 4 bytes (r12) |
| 4 bytes (for align) |
| <- new stack pointer |
| */ |
| fst.d r14, 24, dr0 |
| fst.d r14, 32, dr2 |
| fst.d r14, 40, dr4 |
| fst.d r14, 48, dr6 |
| fst.d r14, 56, dr8 |
| fst.d r14, 64, dr10 |
| st.q r14, 72, r2 |
| st.q r14, 80, r3 |
| st.q r14, 88, r4 |
| st.q r14, 96, r5 |
| st.q r14, 104, r6 |
| st.q r14, 112, r7 |
| st.q r14, 120, r8 |
| st.q r14, 128, r9 |
| |
| add r1, r63, r2 |
| addi r14, 16, r3 |
| addi r14, 72, r4 |
| addi r14, 24, r5 |
| addi r14, 136, r6 |
| #ifdef PIC |
| movi (((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) >> 16) & 65535), r12 |
| shori ((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) & 65535), r12 |
| .LPCS0: ptrel/u r12, tr0 |
| movi ((ffi_closure_helper_SYSV@GOTPLT) & 65535), r1 |
| gettr tr0, r12 |
| ldx.l r1, r12, r1 |
| ptabs r1, tr0 |
| #else |
| pt/l ffi_closure_helper_SYSV, tr0 |
| #endif |
| blink tr0, r18 |
| |
| shlli r2, 1, r1 |
| movi (((datalabel .L_table) >> 16) & 65535), r2 |
| shori ((datalabel .L_table) & 65535), r2 |
| ldx.w r2, r1, r1 |
| add r1, r2, r1 |
| pt/l .L_case_v, tr1 |
| ptabs r1, tr0 |
| blink tr0, r63 |
| |
| .align 2 |
| .L_table: |
| .word .L_case_v - datalabel .L_table /* FFI_TYPE_VOID */ |
| .word .L_case_i - datalabel .L_table /* FFI_TYPE_INT */ |
| .word .L_case_f - datalabel .L_table /* FFI_TYPE_FLOAT */ |
| .word .L_case_d - datalabel .L_table /* FFI_TYPE_DOUBLE */ |
| .word .L_case_d - datalabel .L_table /* FFI_TYPE_LONGDOUBLE */ |
| .word .L_case_uq - datalabel .L_table /* FFI_TYPE_UINT8 */ |
| .word .L_case_q - datalabel .L_table /* FFI_TYPE_SINT8 */ |
| .word .L_case_uh - datalabel .L_table /* FFI_TYPE_UINT16 */ |
| .word .L_case_h - datalabel .L_table /* FFI_TYPE_SINT16 */ |
| .word .L_case_i - datalabel .L_table /* FFI_TYPE_UINT32 */ |
| .word .L_case_i - datalabel .L_table /* FFI_TYPE_SINT32 */ |
| .word .L_case_ll - datalabel .L_table /* FFI_TYPE_UINT64 */ |
| .word .L_case_ll - datalabel .L_table /* FFI_TYPE_SINT64 */ |
| .word .L_case_v - datalabel .L_table /* FFI_TYPE_STRUCT */ |
| .word .L_case_i - datalabel .L_table /* FFI_TYPE_POINTER */ |
| |
| .align 2 |
| .L_case_d: |
| fld.d r14, 16, dr0 |
| blink tr1, r63 |
| .L_case_f: |
| fld.s r14, 16, fr0 |
| blink tr1, r63 |
| .L_case_ll: |
| ld.q r14, 16, r2 |
| blink tr1, r63 |
| .L_case_i: |
| ld.l r14, 16, r2 |
| blink tr1, r63 |
| .L_case_q: |
| ld.b r14, 16, r2 |
| blink tr1, r63 |
| .L_case_uq: |
| ld.ub r14, 16, r2 |
| blink tr1, r63 |
| .L_case_h: |
| ld.w r14, 16, r2 |
| blink tr1, r63 |
| .L_case_uh: |
| ld.uw r14, 16, r2 |
| blink tr1, r63 |
| .L_case_v: |
| add.l r14, r63, r15 |
| ld.l r15, 4, r12 |
| ld.l r15, 8, r14 |
| ld.l r15, 12, r18 |
| addi.l r15, 136, r15 |
| ptabs r18, tr0 |
| blink tr0, r63 |
| |
| .LFE2: |
| .ffi_closure_SYSV_end: |
| .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) |
| |
| #if defined __ELF__ && defined __linux__ |
| .section .note.GNU-stack,"",@progbits |
| #endif |
| |
| .section ".eh_frame","aw",@progbits |
| __FRAME_BEGIN__: |
| .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ |
| .LSCIE1: |
| .4byte 0x0 /* CIE Identifier Tag */ |
| .byte 0x1 /* CIE Version */ |
| #ifdef PIC |
| .ascii "zR\0" /* CIE Augmentation */ |
| #else |
| .byte 0x0 /* CIE Augmentation */ |
| #endif |
| .uleb128 0x1 /* CIE Code Alignment Factor */ |
| .sleb128 -4 /* CIE Data Alignment Factor */ |
| .byte 0x12 /* CIE RA Column */ |
| #ifdef PIC |
| .uleb128 0x1 /* Augmentation size */ |
| .byte 0x10 /* FDE Encoding (pcrel) */ |
| #endif |
| .byte 0xc /* DW_CFA_def_cfa */ |
| .uleb128 0xf |
| .uleb128 0x0 |
| .align 2 |
| .LECIE1: |
| .LSFDE1: |
| .4byte datalabel .LEFDE1-datalabel .LASFDE1 /* FDE Length */ |
| .LASFDE1: |
| .4byte datalabel .LASFDE1-datalabel __FRAME_BEGIN__ |
| #ifdef PIC |
| .4byte .LFB1-. /* FDE initial location */ |
| #else |
| .4byte .LFB1 /* FDE initial location */ |
| #endif |
| .4byte datalabel .LFE1-datalabel .LFB1 /* FDE address range */ |
| #ifdef PIC |
| .uleb128 0x0 /* Augmentation size */ |
| #endif |
| .byte 0x4 /* DW_CFA_advance_loc4 */ |
| .4byte datalabel .LCFI0-datalabel .LFB1 |
| .byte 0xe /* DW_CFA_def_cfa_offset */ |
| .uleb128 0x30 |
| .byte 0x4 /* DW_CFA_advance_loc4 */ |
| .4byte datalabel .LCFI1-datalabel .LCFI0 |
| .byte 0x8e /* DW_CFA_offset, column 0xe */ |
| .uleb128 0xc |
| .byte 0x92 /* DW_CFA_offset, column 0x12 */ |
| .uleb128 0xb |
| .byte 0x9c /* DW_CFA_offset, column 0x1c */ |
| .uleb128 0xa |
| .byte 0x9d /* DW_CFA_offset, column 0x1d */ |
| .uleb128 0x8 |
| .byte 0x9e /* DW_CFA_offset, column 0x1e */ |
| .uleb128 0x6 |
| .byte 0x9f /* DW_CFA_offset, column 0x1f */ |
| .uleb128 0x4 |
| .byte 0xa0 /* DW_CFA_offset, column 0x20 */ |
| .uleb128 0x2 |
| .byte 0x4 /* DW_CFA_advance_loc4 */ |
| .4byte datalabel .LCFI2-datalabel .LCFI1 |
| .byte 0xd /* DW_CFA_def_cfa_register */ |
| .uleb128 0xe |
| .align 2 |
| .LEFDE1: |
| |
| .LSFDE3: |
| .4byte datalabel .LEFDE3-datalabel .LASFDE3 /* FDE Length */ |
| .LASFDE3: |
| .4byte datalabel .LASFDE3-datalabel __FRAME_BEGIN__ |
| #ifdef PIC |
| .4byte .LFB2-. /* FDE initial location */ |
| #else |
| .4byte .LFB2 /* FDE initial location */ |
| #endif |
| .4byte datalabel .LFE2-datalabel .LFB2 /* FDE address range */ |
| #ifdef PIC |
| .uleb128 0x0 /* Augmentation size */ |
| #endif |
| .byte 0x4 /* DW_CFA_advance_loc4 */ |
| .4byte datalabel .LCFI3-datalabel .LFB2 |
| .byte 0xe /* DW_CFA_def_cfa_offset */ |
| .uleb128 0x88 |
| .byte 0x4 /* DW_CFA_advance_loc4 */ |
| .4byte datalabel .LCFI4-datalabel .LCFI3 |
| .byte 0x8c /* DW_CFA_offset, column 0xc */ |
| .uleb128 0x21 |
| .byte 0x8e /* DW_CFA_offset, column 0xe */ |
| .uleb128 0x20 |
| .byte 0x92 /* DW_CFA_offset, column 0x12 */ |
| .uleb128 0x1f |
| .byte 0x4 /* DW_CFA_advance_loc4 */ |
| .4byte datalabel .LCFI5-datalabel .LCFI4 |
| .byte 0xd /* DW_CFA_def_cfa_register */ |
| .uleb128 0xe |
| .align 2 |
| .LEFDE3: |