| /* ----------------------------------------------------------------------- | |
| sysv.S - Copyright (c) 2012 Alan Hourihane | |
| Copyright (c) 1998, 2012 Andreas Schwab | |
| Copyright (c) 2008 Red Hat, Inc. | |
| Copyright (c) 2012, 2016 Thorsten Glaser | |
| m68k 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_AS_CFI_PSEUDO_OP | |
| #define CFI_STARTPROC() .cfi_startproc | |
| #define CFI_OFFSET(reg,off) .cfi_offset reg,off | |
| #define CFI_DEF_CFA(reg,off) .cfi_def_cfa reg,off | |
| #define CFI_ENDPROC() .cfi_endproc | |
| #else | |
| #define CFI_STARTPROC() | |
| #define CFI_OFFSET(reg,off) | |
| #define CFI_DEF_CFA(reg,off) | |
| #define CFI_ENDPROC() | |
| #endif | |
| #ifdef __MINT__ | |
| #define CALLFUNC(funcname) _ ## funcname | |
| #else | |
| #define CALLFUNC(funcname) funcname | |
| #endif | |
| .text | |
| .globl CALLFUNC(ffi_call_SYSV) | |
| .type CALLFUNC(ffi_call_SYSV),@function | |
| .align 4 | |
| CALLFUNC(ffi_call_SYSV): | |
| CFI_STARTPROC() | |
| link %fp,#0 | |
| CFI_OFFSET(14,-8) | |
| CFI_DEF_CFA(14,8) | |
| move.l %d2,-(%sp) | |
| CFI_OFFSET(2,-12) | |
| | Make room for all of the new args. | |
| sub.l 12(%fp),%sp | |
| | Call ffi_prep_args | |
| move.l 8(%fp),-(%sp) | |
| pea 4(%sp) | |
| #if !defined __PIC__ | |
| jsr CALLFUNC(ffi_prep_args) | |
| #elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__) | |
| move.l _current_shared_library_a5_offset_(%a5),%a0 | |
| move.l CALLFUNC(ffi_prep_args@GOT)(%a0),%a0 | |
| jsr (%a0) | |
| #elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__) | |
| move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0 | |
| lea (-6,%pc,%a0),%a0 | |
| move.l CALLFUNC(ffi_prep_args@GOT)(%a0),%a0 | |
| jsr (%a0) | |
| #else | |
| bsr.l CALLFUNC(ffi_prep_args@PLTPC) | |
| #endif | |
| addq.l #8,%sp | |
| | Pass pointer to struct value, if any | |
| #ifdef __MINT__ | |
| move.l %d0,%a1 | |
| #else | |
| move.l %a0,%a1 | |
| #endif | |
| | Call the function | |
| move.l 24(%fp),%a0 | |
| jsr (%a0) | |
| | Remove the space we pushed for the args | |
| add.l 12(%fp),%sp | |
| | Load the pointer to storage for the return value | |
| move.l 20(%fp),%a1 | |
| | Load the return type code | |
| move.l 16(%fp),%d2 | |
| | If the return value pointer is NULL, assume no return value. | |
| | NOTE: On the mc68000, tst on an address register is not supported. | |
| #if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__) | |
| cmp.w #0, %a1 | |
| #else | |
| tst.l %a1 | |
| #endif | |
| jbeq noretval | |
| btst #0,%d2 | |
| jbeq retlongint | |
| move.l %d0,(%a1) | |
| jbra epilogue | |
| retlongint: | |
| btst #1,%d2 | |
| jbeq retfloat | |
| move.l %d0,(%a1) | |
| move.l %d1,4(%a1) | |
| jbra epilogue | |
| retfloat: | |
| btst #2,%d2 | |
| jbeq retdouble | |
| #if defined(__MC68881__) || defined(__HAVE_68881__) | |
| fmove.s %fp0,(%a1) | |
| #else | |
| move.l %d0,(%a1) | |
| #endif | |
| jbra epilogue | |
| retdouble: | |
| btst #3,%d2 | |
| jbeq retlongdouble | |
| #if defined(__MC68881__) || defined(__HAVE_68881__) | |
| fmove.d %fp0,(%a1) | |
| #else | |
| move.l %d0,(%a1)+ | |
| move.l %d1,(%a1) | |
| #endif | |
| jbra epilogue | |
| retlongdouble: | |
| btst #4,%d2 | |
| jbeq retpointer | |
| #if defined(__MC68881__) || defined(__HAVE_68881__) | |
| fmove.x %fp0,(%a1) | |
| #else | |
| move.l %d0,(%a1)+ | |
| move.l %d1,(%a1)+ | |
| move.l %d2,(%a1) | |
| #endif | |
| jbra epilogue | |
| retpointer: | |
| btst #5,%d2 | |
| jbeq retstruct1 | |
| #ifdef __MINT__ | |
| move.l %d0,(%a1) | |
| #else | |
| move.l %a0,(%a1) | |
| #endif | |
| jbra epilogue | |
| retstruct1: | |
| btst #6,%d2 | |
| jbeq retstruct2 | |
| move.b %d0,(%a1) | |
| jbra epilogue | |
| retstruct2: | |
| btst #7,%d2 | |
| jbeq retsint8 | |
| move.w %d0,(%a1) | |
| jbra epilogue | |
| retsint8: | |
| btst #8,%d2 | |
| jbeq retsint16 | |
| | NOTE: On the mc68000, extb is not supported. 8->16, then 16->32. | |
| #if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__) | |
| ext.w %d0 | |
| ext.l %d0 | |
| #else | |
| extb.l %d0 | |
| #endif | |
| move.l %d0,(%a1) | |
| jbra epilogue | |
| retsint16: | |
| btst #9,%d2 | |
| jbeq noretval | |
| ext.l %d0 | |
| move.l %d0,(%a1) | |
| noretval: | |
| epilogue: | |
| move.l (%sp)+,%d2 | |
| unlk %fp | |
| rts | |
| CFI_ENDPROC() | |
| .size CALLFUNC(ffi_call_SYSV),.-CALLFUNC(ffi_call_SYSV) | |
| .globl CALLFUNC(ffi_closure_SYSV) | |
| .type CALLFUNC(ffi_closure_SYSV), @function | |
| .align 4 | |
| CALLFUNC(ffi_closure_SYSV): | |
| CFI_STARTPROC() | |
| link %fp,#-12 | |
| CFI_OFFSET(14,-8) | |
| CFI_DEF_CFA(14,8) | |
| move.l %sp,-12(%fp) | |
| pea 8(%fp) | |
| pea -12(%fp) | |
| move.l %a0,-(%sp) | |
| #if !defined __PIC__ | |
| jsr CALLFUNC(ffi_closure_SYSV_inner) | |
| #elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__) | |
| move.l _current_shared_library_a5_offset_(%a5),%a0 | |
| move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0 | |
| jsr (%a0) | |
| #elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__) | |
| move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0 | |
| lea (-6,%pc,%a0),%a0 | |
| move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0 | |
| jsr (%a0) | |
| #else | |
| bsr.l CALLFUNC(ffi_closure_SYSV_inner@PLTPC) | |
| #endif | |
| lsr.l #1,%d0 | |
| jne 1f | |
| jcc .Lcls_epilogue | |
| | CIF_FLAGS_INT | |
| move.l -12(%fp),%d0 | |
| .Lcls_epilogue: | |
| | no CIF_FLAGS_* | |
| unlk %fp | |
| rts | |
| 1: | |
| lea -12(%fp),%a0 | |
| lsr.l #2,%d0 | |
| jne 1f | |
| jcs .Lcls_ret_float | |
| | CIF_FLAGS_DINT | |
| move.l (%a0)+,%d0 | |
| move.l (%a0),%d1 | |
| jra .Lcls_epilogue | |
| .Lcls_ret_float: | |
| #if defined(__MC68881__) || defined(__HAVE_68881__) | |
| fmove.s (%a0),%fp0 | |
| #else | |
| move.l (%a0),%d0 | |
| #endif | |
| jra .Lcls_epilogue | |
| 1: | |
| lsr.l #2,%d0 | |
| jne 1f | |
| jcs .Lcls_ret_ldouble | |
| | CIF_FLAGS_DOUBLE | |
| #if defined(__MC68881__) || defined(__HAVE_68881__) | |
| fmove.d (%a0),%fp0 | |
| #else | |
| move.l (%a0)+,%d0 | |
| move.l (%a0),%d1 | |
| #endif | |
| jra .Lcls_epilogue | |
| .Lcls_ret_ldouble: | |
| #if defined(__MC68881__) || defined(__HAVE_68881__) | |
| fmove.x (%a0),%fp0 | |
| #else | |
| move.l (%a0)+,%d0 | |
| move.l (%a0)+,%d1 | |
| move.l (%a0),%d2 | |
| #endif | |
| jra .Lcls_epilogue | |
| 1: | |
| lsr.l #2,%d0 | |
| jne 1f | |
| jcs .Lcls_ret_struct1 | |
| | CIF_FLAGS_POINTER | |
| move.l (%a0),%a0 | |
| move.l %a0,%d0 | |
| jra .Lcls_epilogue | |
| .Lcls_ret_struct1: | |
| move.b (%a0),%d0 | |
| jra .Lcls_epilogue | |
| 1: | |
| lsr.l #2,%d0 | |
| jne 1f | |
| jcs .Lcls_ret_sint8 | |
| | CIF_FLAGS_STRUCT2 | |
| move.w (%a0),%d0 | |
| jra .Lcls_epilogue | |
| .Lcls_ret_sint8: | |
| move.l (%a0),%d0 | |
| | NOTE: On the mc68000, extb is not supported. 8->16, then 16->32. | |
| #if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__) | |
| ext.w %d0 | |
| ext.l %d0 | |
| #else | |
| extb.l %d0 | |
| #endif | |
| jra .Lcls_epilogue | |
| 1: | |
| | CIF_FLAGS_SINT16 | |
| move.l (%a0),%d0 | |
| ext.l %d0 | |
| jra .Lcls_epilogue | |
| CFI_ENDPROC() | |
| .size CALLFUNC(ffi_closure_SYSV),.-CALLFUNC(ffi_closure_SYSV) | |
| .globl CALLFUNC(ffi_closure_struct_SYSV) | |
| .type CALLFUNC(ffi_closure_struct_SYSV), @function | |
| .align 4 | |
| CALLFUNC(ffi_closure_struct_SYSV): | |
| CFI_STARTPROC() | |
| link %fp,#0 | |
| CFI_OFFSET(14,-8) | |
| CFI_DEF_CFA(14,8) | |
| move.l %sp,-12(%fp) | |
| pea 8(%fp) | |
| move.l %a1,-(%sp) | |
| move.l %a0,-(%sp) | |
| #if !defined __PIC__ | |
| jsr CALLFUNC(ffi_closure_SYSV_inner) | |
| #elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__) | |
| move.l _current_shared_library_a5_offset_(%a5),%a0 | |
| move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0 | |
| jsr (%a0) | |
| #elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__) | |
| move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0 | |
| lea (-6,%pc,%a0),%a0 | |
| move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0 | |
| jsr (%a0) | |
| #else | |
| bsr.l CALLFUNC(ffi_closure_SYSV_inner@PLTPC) | |
| #endif | |
| unlk %fp | |
| rts | |
| CFI_ENDPROC() | |
| .size CALLFUNC(ffi_closure_struct_SYSV),.-CALLFUNC(ffi_closure_struct_SYSV) | |
| #if defined __ELF__ && defined __linux__ | |
| .section .note.GNU-stack,"",@progbits | |
| #endif |