1 /* ----------------------------------------------------------------------- 2 sysv.S - Copyright (c) 1998, 2008 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, 18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 DEALINGS IN THE SOFTWARE. 25 ----------------------------------------------------------------------- */ 26 27 #define LIBFFI_ASM 28 #include <fficonfig.h> 29 #include <ffi.h> 30 #ifdef HAVE_MACHINE_ASM_H 31 #include <machine/asm.h> 32 #else 33 #ifdef __USER_LABEL_PREFIX__ 34 #define CONCAT1(a, b) CONCAT2(a, b) 35 #define CONCAT2(a, b) a ## b 36 37 /* Use the right prefix for global labels. */ 38 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) 39 #else 40 #define CNAME(x) x 41 #endif 42 #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): 43 #endif 44 45 #ifdef __ELF__ 46 #define LSYM(x) .x 47 #else 48 #define LSYM(x) x 49 #endif 50 51 /* We need a better way of testing for this, but for now, this is all 52 we can do. */ 53 @ This selects the minimum architecture level required. 54 #define __ARM_ARCH__ 3 55 56 #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) 57 # undef __ARM_ARCH__ 58 # define __ARM_ARCH__ 4 59 #endif 60 61 #if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ 62 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ 63 || defined(__ARM_ARCH_5TEJ__) 64 # undef __ARM_ARCH__ 65 # define __ARM_ARCH__ 5 66 #endif 67 68 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ 69 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ 70 || defined(__ARM_ARCH_6ZK__) 71 # undef __ARM_ARCH__ 72 # define __ARM_ARCH__ 6 73 #endif 74 75 #if __ARM_ARCH__ >= 5 76 # define call_reg(x) blx x 77 #elif defined (__ARM_ARCH_4T__) 78 # define call_reg(x) mov lr, pc ; bx x 79 # if defined(__thumb__) || defined(__THUMB_INTERWORK__) 80 # define __INTERWORKING__ 81 # endif 82 #else 83 # define call_reg(x) mov lr, pc ; mov pc, x 84 #endif 85 86 /* Conditionally compile unwinder directives. */ 87 #ifdef __ARM_EABI__ 88 #define UNWIND 89 #else 90 #define UNWIND @ 91 #endif 92 93 94 #if defined(__thumb__) && !defined(__THUMB_INTERWORK__) 95 .macro ARM_FUNC_START name 96 .text 97 .align 0 98 .thumb 99 .thumb_func 100 ENTRY(\name) 101 bx pc 102 nop 103 .arm 104 UNWIND .fnstart 105 /* A hook to tell gdb that we've switched to ARM mode. Also used to call 106 directly from other local arm routines. */ 107 _L__\name: 108 .endm 109 #else 110 .macro ARM_FUNC_START name 111 .text 112 .align 0 113 .arm 114 ENTRY(\name) 115 UNWIND .fnstart 116 .endm 117 #endif 118 119 .macro RETLDM regs=, cond=, dirn=ia 120 #if defined (__INTERWORKING__) 121 .ifc "\regs","" 122 ldr\cond lr, [sp], #4 123 .else 124 ldm\cond\dirn sp!, {\regs, lr} 125 .endif 126 bx\cond lr 127 #else 128 .ifc "\regs","" 129 ldr\cond pc, [sp], #4 130 .else 131 ldm\cond\dirn sp!, {\regs, pc} 132 .endif 133 #endif 134 .endm 135 136 137 @ r0: ffi_prep_args 138 @ r1: &ecif 139 @ r2: cif->bytes 140 @ r3: fig->flags 141 @ sp+0: ecif.rvalue 142 @ sp+4: fn 143 144 @ This assumes we are using gas. 145 ARM_FUNC_START ffi_call_SYSV 146 @ Save registers 147 stmfd sp!, {r0-r3, fp, lr} 148 UNWIND .save {r0-r3, fp, lr} 149 mov fp, sp 150 151 UNWIND .setfp fp, sp 152 153 @ Make room for all of the new args. 154 sub sp, fp, r2 155 156 @ Place all of the ffi_prep_args in position 157 mov ip, r0 158 mov r0, sp 159 @ r1 already set 160 161 @ Call ffi_prep_args(stack, &ecif) 162 call_reg(ip) 163 164 @ move first 4 parameters in registers 165 ldmia sp, {r0-r3} 166 167 @ and adjust stack 168 ldr ip, [fp, #8] 169 cmp ip, #16 170 movhs ip, #16 171 add sp, sp, ip 172 173 @ call (fn) (...) 174 ldr ip, [fp, #28] 175 call_reg(ip) 176 177 @ Remove the space we pushed for the args 178 mov sp, fp 179 180 @ Load r2 with the pointer to storage for the return value 181 ldr r2, [sp, #24] 182 183 @ Load r3 with the return type code 184 ldr r3, [sp, #12] 185 186 @ If the return value pointer is NULL, assume no return value. 187 cmp r2, #0 188 beq LSYM(Lepilogue) 189 190 @ return INT 191 cmp r3, #FFI_TYPE_INT 192 #ifdef __SOFTFP__ 193 cmpne r3, #FFI_TYPE_FLOAT 194 #endif 195 streq r0, [r2] 196 beq LSYM(Lepilogue) 197 198 @ return INT64 199 cmp r3, #FFI_TYPE_SINT64 200 #ifdef __SOFTFP__ 201 cmpne r3, #FFI_TYPE_DOUBLE 202 #endif 203 stmeqia r2, {r0, r1} 204 205 #ifndef __SOFTFP__ 206 beq LSYM(Lepilogue) 207 208 @ return FLOAT 209 cmp r3, #FFI_TYPE_FLOAT 210 stfeqs f0, [r2] 211 beq LSYM(Lepilogue) 212 213 @ return DOUBLE or LONGDOUBLE 214 cmp r3, #FFI_TYPE_DOUBLE 215 stfeqd f0, [r2] 216 #endif 217 218 LSYM(Lepilogue): 219 RETLDM "r0-r3,fp" 220 221 .ffi_call_SYSV_end: 222 UNWIND .fnend 223 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) 224 225 /* 226 unsigned int FFI_HIDDEN 227 ffi_closure_SYSV_inner (closure, respp, args) 228 ffi_closure *closure; 229 void **respp; 230 void *args; 231 */ 232 233 ARM_FUNC_START ffi_closure_SYSV 234 UNWIND .pad #16 235 add ip, sp, #16 236 stmfd sp!, {ip, lr} 237 UNWIND .save {r0, lr} 238 add r2, sp, #8 239 .pad #16 240 sub sp, sp, #16 241 str sp, [sp, #8] 242 add r1, sp, #8 243 bl ffi_closure_SYSV_inner 244 cmp r0, #FFI_TYPE_INT 245 beq .Lretint 246 247 cmp r0, #FFI_TYPE_FLOAT 248 #ifdef __SOFTFP__ 249 beq .Lretint 250 #else 251 beq .Lretfloat 252 #endif 253 254 cmp r0, #FFI_TYPE_DOUBLE 255 #ifdef __SOFTFP__ 256 beq .Lretlonglong 257 #else 258 beq .Lretdouble 259 #endif 260 261 cmp r0, #FFI_TYPE_LONGDOUBLE 262 #ifdef __SOFTFP__ 263 beq .Lretlonglong 264 #else 265 beq .Lretlongdouble 266 #endif 267 268 cmp r0, #FFI_TYPE_SINT64 269 beq .Lretlonglong 270 .Lclosure_epilogue: 271 add sp, sp, #16 272 ldmfd sp, {sp, pc} 273 .Lretint: 274 ldr r0, [sp] 275 b .Lclosure_epilogue 276 .Lretlonglong: 277 ldr r0, [sp] 278 ldr r1, [sp, #4] 279 b .Lclosure_epilogue 280 281 #ifndef __SOFTFP__ 282 .Lretfloat: 283 ldfs f0, [sp] 284 b .Lclosure_epilogue 285 .Lretdouble: 286 ldfd f0, [sp] 287 b .Lclosure_epilogue 288 .Lretlongdouble: 289 ldfd f0, [sp] 290 b .Lclosure_epilogue 291 #endif 292 293 .ffi_closure_SYSV_end: 294 UNWIND .fnend 295 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) 296 297 #if defined __ELF__ && defined __linux__ 298 .section .note.GNU-stack,"",%progbits 299 #endif 300