| /* ----------------------------------------------------------------------- |
| sysv.S - Copyright (c) 2009 Bradley Smith <brad@brad-smith.co.uk> |
| |
| AVR32 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> |
| |
| /* r12: ffi_prep_args |
| * r11: &ecif |
| * r10: size |
| * r9: cif->flags |
| * r8: ecif.rvalue |
| * sp+0: cif->rstruct_flag |
| * sp+4: fn */ |
| |
| .text |
| .align 1 |
| .globl ffi_call_SYSV |
| .type ffi_call_SYSV, @function |
| ffi_call_SYSV: |
| stm --sp, r0,r1,lr |
| stm --sp, r8-r12 |
| mov r0, sp |
| |
| /* Make room for all of the new args. */ |
| sub sp, r10 |
| /* Pad to make way for potential skipped registers */ |
| sub sp, 20 |
| |
| /* Call ffi_prep_args(stack, &ecif). */ |
| /* r11 already set */ |
| mov r1, r12 |
| mov r12, sp |
| icall r1 |
| |
| /* Save new argument size */ |
| mov r1, r12 |
| |
| /* Move first 5 parameters in registers. */ |
| ldm sp++, r8-r12 |
| |
| /* call (fn) (...). */ |
| ld.w r1, r0[36] |
| icall r1 |
| |
| /* Remove the space we pushed for the args. */ |
| mov sp, r0 |
| |
| /* Load r1 with the rstruct flag. */ |
| ld.w r1, sp[32] |
| |
| /* Load r9 with the return type code. */ |
| ld.w r9, sp[12] |
| |
| /* Load r8 with the return value pointer. */ |
| ld.w r8, sp[16] |
| |
| /* If the return value pointer is NULL, assume no return value. */ |
| cp.w r8, 0 |
| breq .Lend |
| |
| /* Check if return type is actually a struct */ |
| cp.w r1, 0 |
| breq 1f |
| |
| /* Return 8bit */ |
| cp.w r9, FFI_TYPE_UINT8 |
| breq .Lstore8 |
| |
| /* Return 16bit */ |
| cp.w r9, FFI_TYPE_UINT16 |
| breq .Lstore16 |
| |
| 1: |
| /* Return 32bit */ |
| cp.w r9, FFI_TYPE_UINT32 |
| breq .Lstore32 |
| cp.w r9, FFI_TYPE_UINT16 |
| breq .Lstore32 |
| cp.w r9, FFI_TYPE_UINT8 |
| breq .Lstore32 |
| |
| /* Return 64bit */ |
| cp.w r9, FFI_TYPE_UINT64 |
| breq .Lstore64 |
| |
| /* Didn't match anything */ |
| bral .Lend |
| |
| .Lstore64: |
| st.w r8[0], r11 |
| st.w r8[4], r10 |
| bral .Lend |
| |
| .Lstore32: |
| st.w r8[0], r12 |
| bral .Lend |
| |
| .Lstore16: |
| st.h r8[0], r12 |
| bral .Lend |
| |
| .Lstore8: |
| st.b r8[0], r12 |
| bral .Lend |
| |
| .Lend: |
| sub sp, -20 |
| ldm sp++, r0,r1,pc |
| |
| .size ffi_call_SYSV, . - ffi_call_SYSV |
| |
| |
| /* r12: __ctx |
| * r11: __rstruct_flag |
| * r10: __inner */ |
| |
| .align 1 |
| .globl ffi_closure_SYSV |
| .type ffi_closure_SYSV, @function |
| ffi_closure_SYSV: |
| stm --sp, r0,lr |
| mov r0, r11 |
| mov r8, r10 |
| sub r10, sp, -8 |
| sub sp, 12 |
| st.w sp[8], sp |
| sub r11, sp, -8 |
| icall r8 |
| |
| /* Check if return type is actually a struct */ |
| cp.w r0, 0 |
| breq 1f |
| |
| /* Return 8bit */ |
| cp.w r12, FFI_TYPE_UINT8 |
| breq .Lget8 |
| |
| /* Return 16bit */ |
| cp.w r12, FFI_TYPE_UINT16 |
| breq .Lget16 |
| |
| 1: |
| /* Return 32bit */ |
| cp.w r12, FFI_TYPE_UINT32 |
| breq .Lget32 |
| cp.w r12, FFI_TYPE_UINT16 |
| breq .Lget32 |
| cp.w r12, FFI_TYPE_UINT8 |
| breq .Lget32 |
| |
| /* Return 64bit */ |
| cp.w r12, FFI_TYPE_UINT64 |
| breq .Lget64 |
| |
| /* Didn't match anything */ |
| bral .Lclend |
| |
| .Lget64: |
| ld.w r11, sp[0] |
| ld.w r10, sp[4] |
| bral .Lclend |
| |
| .Lget32: |
| ld.w r12, sp[0] |
| bral .Lclend |
| |
| .Lget16: |
| ld.uh r12, sp[0] |
| bral .Lclend |
| |
| .Lget8: |
| ld.ub r12, sp[0] |
| bral .Lclend |
| |
| .Lclend: |
| sub sp, -12 |
| ldm sp++, r0,lr |
| sub sp, -20 |
| mov pc, lr |
| |
| .size ffi_closure_SYSV, . - ffi_closure_SYSV |
| |
| #if defined __ELF__ && defined __linux__ |
| .section .note.GNU-stack,"",@progbits |
| #endif |