1/* ----------------------------------------------------------------------- 2 sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. 3 Copyright (c) 2011 Plausible Labs Cooperative, Inc. 4 5 ARM Foreign Function Interface 6 7 Permission is hereby granted, free of charge, to any person obtaining 8 a copy of this software and associated documentation files (the 9 ``Software''), to deal in the Software without restriction, including 10 without limitation the rights to use, copy, modify, merge, publish, 11 distribute, sublicense, and/or sell copies of the Software, and to 12 permit persons to whom the Software is furnished to do so, subject to 13 the following conditions: 14 15 The above copyright notice and this permission notice shall be included 16 in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 ----------------------------------------------------------------------- */ 27 28#define LIBFFI_ASM 29#include <fficonfig.h> 30#include <ffi.h> 31#ifdef HAVE_MACHINE_ASM_H 32#include <machine/asm.h> 33#else 34#ifdef __USER_LABEL_PREFIX__ 35#define CONCAT1(a, b) CONCAT2(a, b) 36#define CONCAT2(a, b) a ## b 37 38/* Use the right prefix for global labels. */ 39#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) 40#else 41#define CNAME(x) x 42#endif 43#ifdef __APPLE__ 44#define ENTRY(x) .globl _##x; _##x: 45#else 46#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): 47#endif /* __APPLE__ */ 48#endif 49 50#ifdef __ELF__ 51#define LSYM(x) .x 52#else 53#define LSYM(x) x 54#endif 55 56/* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI 57 Function Call Guide */ 58#ifdef __APPLE__ 59#define __SOFTFP__ 60#endif 61 62/* We need a better way of testing for this, but for now, this is all 63 we can do. */ 64@ This selects the minimum architecture level required. 65#define __ARM_ARCH__ 3 66 67#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) 68# undef __ARM_ARCH__ 69# define __ARM_ARCH__ 4 70#endif 71 72#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ 73 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ 74 || defined(__ARM_ARCH_5TEJ__) 75# undef __ARM_ARCH__ 76# define __ARM_ARCH__ 5 77#endif 78 79#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ 80 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ 81 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \ 82 || defined(__ARM_ARCH_6M__) 83# undef __ARM_ARCH__ 84# define __ARM_ARCH__ 6 85#endif 86 87#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ 88 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ 89 || defined(__ARM_ARCH_7EM__) 90# undef __ARM_ARCH__ 91# define __ARM_ARCH__ 7 92#endif 93 94#if __ARM_ARCH__ >= 5 95# define call_reg(x) blx x 96#elif defined (__ARM_ARCH_4T__) 97# define call_reg(x) mov lr, pc ; bx x 98# if defined(__thumb__) || defined(__THUMB_INTERWORK__) 99# define __INTERWORKING__ 100# endif 101#else 102# define call_reg(x) mov lr, pc ; mov pc, x 103#endif 104 105/* Conditionally compile unwinder directives. */ 106#ifdef __ARM_EABI__ 107#define UNWIND 108#else 109#define UNWIND @ 110#endif 111 112.syntax unified 113 114#if defined(__thumb__) && !defined(__THUMB_INTERWORK__) 115#define ARM_FUNC_START(name) \ 116 .text; \ 117 .align 2; \ 118 .thumb; \ 119 .thumb_func; \ 120 ENTRY(name); \ 121 bx pc; \ 122 nop; \ 123 .arm; \ 124 UNWIND .fnstart; \ 125_L__##name: 126#else 127#define ARM_FUNC_START(name) \ 128 .text; \ 129 .align 2; \ 130 .arm; \ 131 ENTRY(name); \ 132 UNWIND .fnstart 133#endif 134 135.macro RETLDM regs=, cond=, dirn=ia 136#if defined (__INTERWORKING__) 137 .ifc "\regs","" 138 ldr\cond lr, [sp], #4 139 .else 140 ldm\cond\dirn sp!, {\regs, lr} 141 .endif 142 bx\cond lr 143#else 144 .ifc "\regs","" 145 ldr\cond pc, [sp], #4 146 .else 147 ldm\cond\dirn sp!, {\regs, pc} 148 .endif 149#endif 150.endm 151 152 @ r0: ffi_prep_args 153 @ r1: &ecif 154 @ r2: cif->bytes 155 @ r3: fig->flags 156 @ sp+0: ecif.rvalue 157 158 @ This assumes we are using gas. 159ARM_FUNC_START(ffi_call_SYSV) 160 @ Save registers 161 stmfd sp!, {r0-r3, fp, lr} 162 UNWIND .save {r0-r3, fp, lr} 163 mov fp, sp 164 165 UNWIND .setfp fp, sp 166 167 @ Make room for all of the new args. 168 sub sp, fp, r2 169 170 @ Place all of the ffi_prep_args in position 171 mov r0, sp 172 @ r1 already set 173 174 @ Call ffi_prep_args(stack, &ecif) 175 bl CNAME(ffi_prep_args_SYSV) 176 177 @ move first 4 parameters in registers 178 ldmia sp, {r0-r3} 179 180 @ and adjust stack 181 sub lr, fp, sp @ cif->bytes == fp - sp 182 ldr ip, [fp] @ load fn() in advance 183 cmp lr, #16 184 movhs lr, #16 185 add sp, sp, lr 186 187 @ call (fn) (...) 188 call_reg(ip) 189 190 @ Remove the space we pushed for the args 191 mov sp, fp 192 193 @ Load r2 with the pointer to storage for the return value 194 ldr r2, [sp, #24] 195 196 @ Load r3 with the return type code 197 ldr r3, [sp, #12] 198 199 @ If the return value pointer is NULL, assume no return value. 200 cmp r2, #0 201 beq LSYM(Lepilogue) 202 203@ return INT 204 cmp r3, #FFI_TYPE_INT 205#if defined(__SOFTFP__) || defined(__ARM_EABI__) 206 cmpne r3, #FFI_TYPE_FLOAT 207#endif 208 streq r0, [r2] 209 beq LSYM(Lepilogue) 210 211 @ return INT64 212 cmp r3, #FFI_TYPE_SINT64 213#if defined(__SOFTFP__) || defined(__ARM_EABI__) 214 cmpne r3, #FFI_TYPE_DOUBLE 215#endif 216 stmiaeq r2, {r0, r1} 217 218#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) 219 beq LSYM(Lepilogue) 220 221@ return FLOAT 222 cmp r3, #FFI_TYPE_FLOAT 223 stfeqs f0, [r2] 224 beq LSYM(Lepilogue) 225 226@ return DOUBLE or LONGDOUBLE 227 cmp r3, #FFI_TYPE_DOUBLE 228 stfeqd f0, [r2] 229#endif 230 231LSYM(Lepilogue): 232#if defined (__INTERWORKING__) 233 ldmia sp!, {r0-r3,fp, lr} 234 bx lr 235#else 236 ldmia sp!, {r0-r3,fp, pc} 237#endif 238 239.ffi_call_SYSV_end: 240 UNWIND .fnend 241#ifdef __ELF__ 242 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) 243#endif 244 245 246/* 247 unsigned int FFI_HIDDEN 248 ffi_closure_inner (closure, respp, args) 249 ffi_closure *closure; 250 void **respp; 251 void *args; 252*/ 253 254ARM_FUNC_START(ffi_closure_SYSV) 255 UNWIND .pad #16 256 add ip, sp, #16 257 stmfd sp!, {ip, lr} 258 UNWIND .save {r0, lr} 259 add r2, sp, #8 260 UNWIND .pad #16 261 sub sp, sp, #16 262 str sp, [sp, #8] 263 add r1, sp, #8 264 bl CNAME(ffi_closure_inner) 265 cmp r0, #FFI_TYPE_INT 266 beq .Lretint 267 268 cmp r0, #FFI_TYPE_FLOAT 269#if defined(__SOFTFP__) || defined(__ARM_EABI__) 270 beq .Lretint 271#else 272 beq .Lretfloat 273#endif 274 275 cmp r0, #FFI_TYPE_DOUBLE 276#if defined(__SOFTFP__) || defined(__ARM_EABI__) 277 beq .Lretlonglong 278#else 279 beq .Lretdouble 280#endif 281 282 cmp r0, #FFI_TYPE_LONGDOUBLE 283#if defined(__SOFTFP__) || defined(__ARM_EABI__) 284 beq .Lretlonglong 285#else 286 beq .Lretlongdouble 287#endif 288 289 cmp r0, #FFI_TYPE_SINT64 290 beq .Lretlonglong 291.Lclosure_epilogue: 292 add sp, sp, #16 293 ldmfd sp, {sp, pc} 294.Lretint: 295 ldr r0, [sp] 296 b .Lclosure_epilogue 297.Lretlonglong: 298 ldr r0, [sp] 299 ldr r1, [sp, #4] 300 b .Lclosure_epilogue 301 302#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) 303.Lretfloat: 304 ldfs f0, [sp] 305 b .Lclosure_epilogue 306.Lretdouble: 307 ldfd f0, [sp] 308 b .Lclosure_epilogue 309.Lretlongdouble: 310 ldfd f0, [sp] 311 b .Lclosure_epilogue 312#endif 313 314.ffi_closure_SYSV_end: 315 UNWIND .fnend 316#ifdef __ELF__ 317 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) 318#endif 319 320 321/* Below are VFP hard-float ABI call and closure implementations. 322 Add VFP FPU directive here. This is only compiled into the library 323 under EABI. */ 324#ifdef __ARM_EABI__ 325 .fpu vfp 326 327 @ r0: fn 328 @ r1: &ecif 329 @ r2: cif->bytes 330 @ r3: fig->flags 331 @ sp+0: ecif.rvalue 332 333ARM_FUNC_START(ffi_call_VFP) 334 @ Save registers 335 stmfd sp!, {r0-r3, fp, lr} 336 UNWIND .save {r0-r3, fp, lr} 337 mov fp, sp 338 UNWIND .setfp fp, sp 339 340 @ Make room for all of the new args. 341 sub sp, sp, r2 342 343 @ Make room for loading VFP args 344 sub sp, sp, #64 345 346 @ Place all of the ffi_prep_args in position 347 mov r0, sp 348 @ r1 already set 349 sub r2, fp, #64 @ VFP scratch space 350 351 @ Call ffi_prep_args(stack, &ecif, vfp_space) 352 bl CNAME(ffi_prep_args_VFP) 353 354 @ Load VFP register args if needed 355 cmp r0, #0 356 mov ip, fp 357 beq LSYM(Lbase_args) 358 359 @ Load only d0 if possible 360 cmp r0, #3 361 sub ip, fp, #64 362 flddle d0, [ip] 363 vldmiagt ip, {d0-d7} 364 365LSYM(Lbase_args): 366 @ move first 4 parameters in registers 367 ldmia sp, {r0-r3} 368 369 @ and adjust stack 370 sub lr, ip, sp @ cif->bytes == (fp - 64) - sp 371 ldr ip, [fp] @ load fn() in advance 372 cmp lr, #16 373 movhs lr, #16 374 add sp, sp, lr 375 376 @ call (fn) (...) 377 call_reg(ip) 378 379 @ Remove the space we pushed for the args 380 mov sp, fp 381 382 @ Load r2 with the pointer to storage for 383 @ the return value 384 ldr r2, [sp, #24] 385 386 @ Load r3 with the return type code 387 ldr r3, [sp, #12] 388 389 @ If the return value pointer is NULL, 390 @ assume no return value. 391 cmp r2, #0 392 beq LSYM(Lepilogue_vfp) 393 394 cmp r3, #FFI_TYPE_INT 395 streq r0, [r2] 396 beq LSYM(Lepilogue_vfp) 397 398 cmp r3, #FFI_TYPE_SINT64 399 stmiaeq r2, {r0, r1} 400 beq LSYM(Lepilogue_vfp) 401 402 cmp r3, #FFI_TYPE_FLOAT 403 fstseq s0, [r2] 404 beq LSYM(Lepilogue_vfp) 405 406 cmp r3, #FFI_TYPE_DOUBLE 407 fstdeq d0, [r2] 408 beq LSYM(Lepilogue_vfp) 409 410 cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT 411 cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE 412 vstmiaeq r2, {d0-d3} 413 414LSYM(Lepilogue_vfp): 415 RETLDM "r0-r3,fp" 416 417.ffi_call_VFP_end: 418 UNWIND .fnend 419 .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP) 420 421 422ARM_FUNC_START(ffi_closure_VFP) 423 vpush {d0-d7} 424 @ r0-r3, then d0-d7 425 UNWIND .pad #80 426 add ip, sp, #80 427 stmfd sp!, {ip, lr} 428 UNWIND .save {r0, lr} 429 add r2, sp, #72 430 add r3, sp, #8 431 UNWIND .pad #72 432 sub sp, sp, #72 433 str sp, [sp, #64] 434 add r1, sp, #64 435 bl CNAME(ffi_closure_inner) 436 437 cmp r0, #FFI_TYPE_INT 438 beq .Lretint_vfp 439 440 cmp r0, #FFI_TYPE_FLOAT 441 beq .Lretfloat_vfp 442 443 cmp r0, #FFI_TYPE_DOUBLE 444 cmpne r0, #FFI_TYPE_LONGDOUBLE 445 beq .Lretdouble_vfp 446 447 cmp r0, #FFI_TYPE_SINT64 448 beq .Lretlonglong_vfp 449 450 cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT 451 beq .Lretfloat_struct_vfp 452 453 cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE 454 beq .Lretdouble_struct_vfp 455 456.Lclosure_epilogue_vfp: 457 add sp, sp, #72 458 ldmfd sp, {sp, pc} 459 460.Lretfloat_vfp: 461 flds s0, [sp] 462 b .Lclosure_epilogue_vfp 463.Lretdouble_vfp: 464 fldd d0, [sp] 465 b .Lclosure_epilogue_vfp 466.Lretint_vfp: 467 ldr r0, [sp] 468 b .Lclosure_epilogue_vfp 469.Lretlonglong_vfp: 470 ldmia sp, {r0, r1} 471 b .Lclosure_epilogue_vfp 472.Lretfloat_struct_vfp: 473 vldmia sp, {d0-d1} 474 b .Lclosure_epilogue_vfp 475.Lretdouble_struct_vfp: 476 vldmia sp, {d0-d3} 477 b .Lclosure_epilogue_vfp 478 479.ffi_closure_VFP_end: 480 UNWIND .fnend 481 .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP) 482#endif 483 484ENTRY(ffi_arm_trampoline) 485 stmfd sp!, {r0-r3} 486 ldr r0, [pc] 487 ldr pc, [pc] 488 489#if defined __ELF__ && defined __linux__ 490 .section .note.GNU-stack,"",%progbits 491#endif 492