| /* ----------------------------------------------------------------------- | |
| sysv.S - Copyright (c) 2000 Software AG | |
| Copyright (c) 2008 Red Hat, Inc. | |
| S390 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> | |
| .text | |
| #ifndef __s390x__ | |
| # r2: frame | |
| # r3: ret_type | |
| # r4: ret_addr | |
| # r5: fun | |
| # r6: closure | |
| # This assumes we are using gas. | |
| .balign 8 | |
| .globl ffi_call_SYSV | |
| FFI_HIDDEN(ffi_call_SYSV) | |
| .type ffi_call_SYSV,%function | |
| ffi_call_SYSV: | |
| .cfi_startproc | |
| st %r6,44(%r2) # Save registers | |
| stm %r12,%r14,48(%r2) | |
| lr %r13,%r2 # Install frame pointer | |
| .cfi_rel_offset r6, 44 | |
| .cfi_rel_offset r12, 48 | |
| .cfi_rel_offset r13, 52 | |
| .cfi_rel_offset r14, 56 | |
| .cfi_def_cfa_register r13 | |
| st %r2,0(%r15) # Set up back chain | |
| sla %r3,3 # ret_type *= 8 | |
| lr %r12,%r4 # Save ret_addr | |
| lr %r1,%r5 # Save fun | |
| lr %r0,%r6 # Install static chain | |
| # Set return address, so that there is only one indirect jump. | |
| #ifdef HAVE_AS_S390_ZARCH | |
| larl %r14,.Ltable | |
| ar %r14,%r3 | |
| #else | |
| basr %r14,0 | |
| 0: la %r14,.Ltable-0b(%r14,%r3) | |
| #endif | |
| lm %r2,%r6,8(%r13) # Load arguments | |
| ld %f0,64(%r13) | |
| ld %f2,72(%r13) | |
| br %r1 # ... and call function | |
| .balign 8 | |
| .Ltable: | |
| # FFI390_RET_DOUBLE | |
| std %f0,0(%r12) | |
| j .Ldone | |
| .balign 8 | |
| # FFI390_RET_FLOAT | |
| ste %f0,0(%r12) | |
| j .Ldone | |
| .balign 8 | |
| # FFI390_RET_INT64 | |
| st %r3,4(%r12) | |
| nop | |
| # fallthru | |
| .balign 8 | |
| # FFI390_RET_INT32 | |
| st %r2,0(%r12) | |
| nop | |
| # fallthru | |
| .balign 8 | |
| # FFI390_RET_VOID | |
| .Ldone: | |
| l %r14,56(%r13) | |
| l %r12,48(%r13) | |
| l %r6,44(%r13) | |
| l %r13,52(%r13) | |
| .cfi_restore 14 | |
| .cfi_restore 13 | |
| .cfi_restore 12 | |
| .cfi_restore 6 | |
| .cfi_def_cfa r15, 96 | |
| br %r14 | |
| .cfi_endproc | |
| .size ffi_call_SYSV,.-ffi_call_SYSV | |
| .balign 8 | |
| .globl ffi_go_closure_SYSV | |
| FFI_HIDDEN(ffi_go_closure_SYSV) | |
| .type ffi_go_closure_SYSV,%function | |
| ffi_go_closure_SYSV: | |
| .cfi_startproc | |
| stm %r2,%r6,8(%r15) # Save arguments | |
| lr %r4,%r0 # Load closure -> user_data | |
| l %r2,4(%r4) # ->cif | |
| l %r3,8(%r4) # ->fun | |
| j .Ldoclosure | |
| .cfi_endproc | |
| .balign 8 | |
| .globl ffi_closure_SYSV | |
| FFI_HIDDEN(ffi_closure_SYSV) | |
| .type ffi_closure_SYSV,%function | |
| ffi_closure_SYSV: | |
| .cfi_startproc | |
| stm %r2,%r6,8(%r15) # Save arguments | |
| lr %r4,%r0 # Closure | |
| l %r2,16(%r4) # ->cif | |
| l %r3,20(%r4) # ->fun | |
| l %r4,24(%r4) # ->user_data | |
| .Ldoclosure: | |
| stm %r12,%r15,48(%r15) # Save registers | |
| lr %r12,%r15 | |
| .cfi_def_cfa_register r12 | |
| .cfi_rel_offset r6, 24 | |
| .cfi_rel_offset r12, 48 | |
| .cfi_rel_offset r13, 52 | |
| .cfi_rel_offset r14, 56 | |
| .cfi_rel_offset r15, 60 | |
| #ifndef HAVE_AS_S390_ZARCH | |
| basr %r13,0 # Set up base register | |
| .Lcbase: | |
| l %r1,.Lchelper-.Lcbase(%r13) # Get helper function | |
| #endif | |
| ahi %r15,-96-8 # Set up stack frame | |
| st %r12,0(%r15) # Set up back chain | |
| std %f0,64(%r12) # Save fp arguments | |
| std %f2,72(%r12) | |
| la %r5,96(%r12) # Overflow | |
| st %r5,96(%r15) | |
| la %r6,64(%r12) # FPRs | |
| la %r5,8(%r12) # GPRs | |
| #ifdef HAVE_AS_S390_ZARCH | |
| brasl %r14,ffi_closure_helper_SYSV | |
| #else | |
| bas %r14,0(%r1,%r13) # Call helper | |
| #endif | |
| lr %r15,%r12 | |
| .cfi_def_cfa_register r15 | |
| lm %r12,%r14,48(%r12) # Restore saved registers | |
| l %r6,24(%r15) | |
| ld %f0,64(%r15) # Load return registers | |
| lm %r2,%r3,8(%r15) | |
| br %r14 | |
| .cfi_endproc | |
| #ifndef HAVE_AS_S390_ZARCH | |
| .align 4 | |
| .Lchelper: | |
| .long ffi_closure_helper_SYSV-.Lcbase | |
| #endif | |
| .size ffi_closure_SYSV,.-ffi_closure_SYSV | |
| #else | |
| # r2: frame | |
| # r3: ret_type | |
| # r4: ret_addr | |
| # r5: fun | |
| # r6: closure | |
| # This assumes we are using gas. | |
| .balign 8 | |
| .globl ffi_call_SYSV | |
| FFI_HIDDEN(ffi_call_SYSV) | |
| .type ffi_call_SYSV,%function | |
| ffi_call_SYSV: | |
| .cfi_startproc | |
| stg %r6,88(%r2) # Save registers | |
| stmg %r12,%r14,96(%r2) | |
| lgr %r13,%r2 # Install frame pointer | |
| .cfi_rel_offset r6, 88 | |
| .cfi_rel_offset r12, 96 | |
| .cfi_rel_offset r13, 104 | |
| .cfi_rel_offset r14, 112 | |
| .cfi_def_cfa_register r13 | |
| stg %r2,0(%r15) # Set up back chain | |
| larl %r14,.Ltable # Set up return address | |
| slag %r3,%r3,3 # ret_type *= 8 | |
| lgr %r12,%r4 # Save ret_addr | |
| lgr %r1,%r5 # Save fun | |
| lgr %r0,%r6 # Install static chain | |
| agr %r14,%r3 | |
| lmg %r2,%r6,16(%r13) # Load arguments | |
| ld %f0,128(%r13) | |
| ld %f2,136(%r13) | |
| ld %f4,144(%r13) | |
| ld %f6,152(%r13) | |
| br %r1 # ... and call function | |
| .balign 8 | |
| .Ltable: | |
| # FFI390_RET_DOUBLE | |
| std %f0,0(%r12) | |
| j .Ldone | |
| .balign 8 | |
| # FFI390_RET_DOUBLE | |
| ste %f0,0(%r12) | |
| j .Ldone | |
| .balign 8 | |
| # FFI390_RET_INT64 | |
| stg %r2,0(%r12) | |
| .balign 8 | |
| # FFI390_RET_INT32 | |
| # Never used, as we always store type ffi_arg. | |
| # But the stg above is 6 bytes and we cannot | |
| # jump around this case, so fall through. | |
| nop | |
| nop | |
| .balign 8 | |
| # FFI390_RET_VOID | |
| .Ldone: | |
| lg %r14,112(%r13) | |
| lg %r12,96(%r13) | |
| lg %r6,88(%r13) | |
| lg %r13,104(%r13) | |
| .cfi_restore r14 | |
| .cfi_restore r13 | |
| .cfi_restore r12 | |
| .cfi_restore r6 | |
| .cfi_def_cfa r15, 160 | |
| br %r14 | |
| .cfi_endproc | |
| .size ffi_call_SYSV,.-ffi_call_SYSV | |
| .balign 8 | |
| .globl ffi_go_closure_SYSV | |
| FFI_HIDDEN(ffi_go_closure_SYSV) | |
| .type ffi_go_closure_SYSV,%function | |
| ffi_go_closure_SYSV: | |
| .cfi_startproc | |
| stmg %r2,%r6,16(%r15) # Save arguments | |
| lgr %r4,%r0 # Load closure -> user_data | |
| lg %r2,8(%r4) # ->cif | |
| lg %r3,16(%r4) # ->fun | |
| j .Ldoclosure | |
| .cfi_endproc | |
| .size ffi_go_closure_SYSV,.-ffi_go_closure_SYSV | |
| .balign 8 | |
| .globl ffi_closure_SYSV | |
| FFI_HIDDEN(ffi_closure_SYSV) | |
| .type ffi_closure_SYSV,%function | |
| ffi_closure_SYSV: | |
| .cfi_startproc | |
| stmg %r2,%r6,16(%r15) # Save arguments | |
| lgr %r4,%r0 # Load closure | |
| lg %r2,32(%r4) # ->cif | |
| lg %r3,40(%r4) # ->fun | |
| lg %r4,48(%r4) # ->user_data | |
| .Ldoclosure: | |
| stmg %r13,%r15,104(%r15) # Save registers | |
| lgr %r13,%r15 | |
| .cfi_def_cfa_register r13 | |
| .cfi_rel_offset r6, 48 | |
| .cfi_rel_offset r13, 104 | |
| .cfi_rel_offset r14, 112 | |
| .cfi_rel_offset r15, 120 | |
| aghi %r15,-160-16 # Set up stack frame | |
| stg %r13,0(%r15) # Set up back chain | |
| std %f0,128(%r13) # Save fp arguments | |
| std %f2,136(%r13) | |
| std %f4,144(%r13) | |
| std %f6,152(%r13) | |
| la %r5,160(%r13) # Overflow | |
| stg %r5,160(%r15) | |
| la %r6,128(%r13) # FPRs | |
| la %r5,16(%r13) # GPRs | |
| brasl %r14,ffi_closure_helper_SYSV # Call helper | |
| lgr %r15,%r13 | |
| .cfi_def_cfa_register r15 | |
| lmg %r13,%r14,104(%r13) # Restore saved registers | |
| lg %r6,48(%r15) | |
| ld %f0,128(%r15) # Load return registers | |
| lg %r2,16(%r15) | |
| br %r14 | |
| .cfi_endproc | |
| .size ffi_closure_SYSV,.-ffi_closure_SYSV | |
| #endif /* !s390x */ | |
| #if defined __ELF__ && defined __linux__ | |
| .section .note.GNU-stack,"",@progbits | |
| #endif |