1 ; ----------------------------------------------------------------------- 2 ; sysv.S - Copyright (c) 1998 Red Hat, Inc. 3 ; 4 ; ARM Foreign Function Interface 5 ; 6 ; Permission is hereby granted, free of charge, to any person obtaining 7 ; a copy of this software and associated documentation files (the 8 ; ``Software''), to deal in the Software without restriction, including 9 ; without limitation the rights to use, copy, modify, merge, publish, 10 ; distribute, sublicense, and/or sell copies of the Software, and to 11 ; permit persons to whom the Software is furnished to do so, subject to 12 ; the following conditions: 13 ; 14 ; The above copyright notice and this permission notice shall be included 15 ; in all copies or substantial portions of the Software. 16 ; 17 ; THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 ; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 ; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 ; IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 ; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 ; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 ; OTHER DEALINGS IN THE SOFTWARE. 24 ; ----------------------------------------------------------------------- */ 25 26 ;#define LIBFFI_ASM 27 ;#include <fficonfig.h> 28 ;#include <ffi.h> 29 ;#ifdef HAVE_MACHINE_ASM_H 30 ;#include <machine/asm.h> 31 ;#else 32 ;#ifdef __USER_LABEL_PREFIX__ 33 ;#define CONCAT1(a, b) CONCAT2(a, b) 34 ;#define CONCAT2(a, b) a ## b 35 36 ;/* Use the right prefix for global labels. */ 37 ;#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) 38 ;#else 39 ;#define CNAME(x) x 40 ;#endif 41 ;#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): 42 ;#endif 43 44 45 FFI_TYPE_VOID EQU 0 46 FFI_TYPE_INT EQU 1 47 FFI_TYPE_FLOAT EQU 2 48 FFI_TYPE_DOUBLE EQU 3 49 ;FFI_TYPE_LONGDOUBLE EQU 4 50 FFI_TYPE_UINT8 EQU 5 51 FFI_TYPE_SINT8 EQU 6 52 FFI_TYPE_UINT16 EQU 7 53 FFI_TYPE_SINT16 EQU 8 54 FFI_TYPE_UINT32 EQU 9 55 FFI_TYPE_SINT32 EQU 10 56 FFI_TYPE_UINT64 EQU 11 57 FFI_TYPE_SINT64 EQU 12 58 FFI_TYPE_STRUCT EQU 13 59 FFI_TYPE_POINTER EQU 14 60 61 ; WinCE always uses software floating point (I think) 62 __SOFTFP__ EQU {TRUE} 63 64 65 AREA |.text|, CODE, ARM ; .text 66 67 68 ; a1: ffi_prep_args 69 ; a2: &ecif 70 ; a3: cif->bytes 71 ; a4: fig->flags 72 ; sp+0: ecif.rvalue 73 ; sp+4: fn 74 75 ; This assumes we are using gas. 76 ;ENTRY(ffi_call_SYSV) 77 78 EXPORT |ffi_call_SYSV| 79 80 |ffi_call_SYSV| PROC 81 82 ; Save registers 83 stmfd sp!, {a1-a4, fp, lr} 84 mov fp, sp 85 86 ; Make room for all of the new args. 87 sub sp, fp, a3 88 89 ; Place all of the ffi_prep_args in position 90 mov ip, a1 91 mov a1, sp 92 ; a2 already set 93 94 ; And call 95 mov lr, pc 96 mov pc, ip 97 98 ; move first 4 parameters in registers 99 ldr a1, [sp, #0] 100 ldr a2, [sp, #4] 101 ldr a3, [sp, #8] 102 ldr a4, [sp, #12] 103 104 ; and adjust stack 105 ldr ip, [fp, #8] 106 cmp ip, #16 107 movge ip, #16 108 add sp, sp, ip 109 110 ; call function 111 mov lr, pc 112 ldr pc, [fp, #28] 113 114 ; Remove the space we pushed for the args 115 mov sp, fp 116 117 ; Load a3 with the pointer to storage for the return value 118 ldr a3, [sp, #24] 119 120 ; Load a4 with the return type code 121 ldr a4, [sp, #12] 122 123 ; If the return value pointer is NULL, assume no return value. 124 cmp a3, #0 125 beq call_epilogue 126 127 ; return INT 128 cmp a4, #FFI_TYPE_INT 129 streq a1, [a3] 130 beq call_epilogue 131 132 ; return FLOAT 133 cmp a4, #FFI_TYPE_FLOAT 134 [ __SOFTFP__ ;ifdef __SOFTFP__ 135 streq a1, [a3] 136 | ;else 137 stfeqs f0, [a3] 138 ] ;endif 139 beq call_epilogue 140 141 ; return DOUBLE or LONGDOUBLE 142 cmp a4, #FFI_TYPE_DOUBLE 143 [ __SOFTFP__ ;ifdef __SOFTFP__ 144 stmeqia a3, {a1, a2} 145 | ;else 146 stfeqd f0, [a3] 147 ] ;endif 148 beq call_epilogue 149 150 ; return SINT64 or UINT64 151 cmp a4, #FFI_TYPE_SINT64 152 stmeqia a3, {a1, a2} 153 154 call_epilogue 155 ldmfd sp!, {a1-a4, fp, pc} 156 157 ;.ffi_call_SYSV_end: 158 ;.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) 159 ENDP 160 161 162 RESERVE_RETURN EQU 16 163 164 ; This function is called by the trampoline 165 ; It is NOT callable from C 166 ; ip = pointer to struct ffi_closure 167 168 IMPORT |ffi_closure_SYSV_inner| 169 170 EXPORT |ffi_closure_SYSV| 171 |ffi_closure_SYSV| PROC 172 173 ; Store the argument registers on the stack 174 stmfd sp!, {a1-a4} 175 ; Push the return address onto the stack 176 stmfd sp!, {lr} 177 178 mov a1, ip ; first arg = address of ffi_closure 179 add a2, sp, #4 ; second arg = sp+4 (points to saved a1) 180 181 ; Allocate space for a non-struct return value 182 sub sp, sp, #RESERVE_RETURN 183 mov a3, sp ; third arg = return value address 184 185 ; static unsigned int 186 ; ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue) 187 bl ffi_closure_SYSV_inner 188 ; a1 now contains the return type code 189 190 ; At this point the return value is on the stack 191 ; Transfer it to the correct registers if necessary 192 193 ; return INT 194 cmp a1, #FFI_TYPE_INT 195 ldreq a1, [sp] 196 beq closure_epilogue 197 198 ; return FLOAT 199 cmp a1, #FFI_TYPE_FLOAT 200 [ __SOFTFP__ ;ifdef __SOFTFP__ 201 ldreq a1, [sp] 202 | ;else 203 stfeqs f0, [sp] 204 ] ;endif 205 beq closure_epilogue 206 207 ; return DOUBLE or LONGDOUBLE 208 cmp a1, #FFI_TYPE_DOUBLE 209 [ __SOFTFP__ ;ifdef __SOFTFP__ 210 ldmeqia sp, {a1, a2} 211 | ;else 212 stfeqd f0, [sp] 213 ] ;endif 214 beq closure_epilogue 215 216 ; return SINT64 or UINT64 217 cmp a1, #FFI_TYPE_SINT64 218 ldmeqia sp, {a1, a2} 219 220 closure_epilogue 221 add sp, sp, #RESERVE_RETURN ; remove return value buffer 222 ldmfd sp!, {ip} ; ip = pop return address 223 add sp, sp, #16 ; remove saved argument registers {a1-a4} from the stack 224 mov pc, ip ; return 225 226 ENDP ; ffi_closure_SYSV 227 228 END 229