sysv.S revision 46ce27ab1e22ca98957e0900c6a2415b86578b2e
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 113#if defined(__thumb__) && !defined(__THUMB_INTERWORK__) 114.macro ARM_FUNC_START name 115 .text 116 .align 0 117 .thumb 118 .thumb_func 119#ifdef __APPLE__ 120 ENTRY($0) 121#else 122 ENTRY(\name) 123#endif 124 bx pc 125 nop 126 .arm 127 UNWIND .fnstart 128/* A hook to tell gdb that we've switched to ARM mode. Also used to call 129 directly from other local arm routines. */ 130#ifdef __APPLE__ 131_L__$0: 132#else 133_L__\name: 134#endif 135.endm 136#else 137.macro ARM_FUNC_START name 138 .text 139 .align 0 140 .arm 141#ifdef __APPLE__ 142 ENTRY($0) 143#else 144 ENTRY(\name) 145#endif 146 UNWIND .fnstart 147.endm 148#endif 149 150.macro RETLDM regs=, cond=, dirn=ia 151#if defined (__INTERWORKING__) 152 .ifc "\regs","" 153 ldr\cond lr, [sp], #4 154 .else 155 ldm\cond\dirn sp!, {\regs, lr} 156 .endif 157 bx\cond lr 158#else 159 .ifc "\regs","" 160 ldr\cond pc, [sp], #4 161 .else 162 ldm\cond\dirn sp!, {\regs, pc} 163 .endif 164#endif 165.endm 166 167 @ r0: ffi_prep_args 168 @ r1: &ecif 169 @ r2: cif->bytes 170 @ r3: fig->flags 171 @ sp+0: ecif.rvalue 172 173 @ This assumes we are using gas. 174ARM_FUNC_START ffi_call_SYSV 175 @ Save registers 176 stmfd sp!, {r0-r3, fp, lr} 177 UNWIND .save {r0-r3, fp, lr} 178 mov fp, sp 179 180 UNWIND .setfp fp, sp 181 182 @ Make room for all of the new args. 183 sub sp, fp, r2 184 185 @ Place all of the ffi_prep_args in position 186 mov r0, sp 187 @ r1 already set 188 189 @ Call ffi_prep_args(stack, &ecif) 190 bl CNAME(ffi_prep_args) 191 192 @ move first 4 parameters in registers 193 ldmia sp, {r0-r3} 194 195 @ and adjust stack 196 sub lr, fp, sp @ cif->bytes == fp - sp 197 ldr ip, [fp] @ load fn() in advance 198 cmp lr, #16 199 movhs lr, #16 200 add sp, sp, lr 201 202 @ call (fn) (...) 203 call_reg(ip) 204 205 @ Remove the space we pushed for the args 206 mov sp, fp 207 208 @ Load r2 with the pointer to storage for the return value 209 ldr r2, [sp, #24] 210 211 @ Load r3 with the return type code 212 ldr r3, [sp, #12] 213 214 @ If the return value pointer is NULL, assume no return value. 215 cmp r2, #0 216 beq LSYM(Lepilogue) 217 218@ return INT 219 cmp r3, #FFI_TYPE_INT 220#if defined(__SOFTFP__) || defined(__ARM_EABI__) 221 cmpne r3, #FFI_TYPE_FLOAT 222#endif 223 streq r0, [r2] 224 beq LSYM(Lepilogue) 225 226 @ return INT64 227 cmp r3, #FFI_TYPE_SINT64 228#if defined(__SOFTFP__) || defined(__ARM_EABI__) 229 cmpne r3, #FFI_TYPE_DOUBLE 230#endif 231 stmeqia r2, {r0, r1} 232 233#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) 234 beq LSYM(Lepilogue) 235 236@ return FLOAT 237 cmp r3, #FFI_TYPE_FLOAT 238 stfeqs f0, [r2] 239 beq LSYM(Lepilogue) 240 241@ return DOUBLE or LONGDOUBLE 242 cmp r3, #FFI_TYPE_DOUBLE 243 stfeqd f0, [r2] 244#endif 245 246LSYM(Lepilogue): 247#if defined (__INTERWORKING__) 248 ldmia sp!, {r0-r3,fp, lr} 249 bx lr 250#else 251 ldmia sp!, {r0-r3,fp, pc} 252#endif 253 254.ffi_call_SYSV_end: 255 UNWIND .fnend 256#ifdef __ELF__ 257 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) 258#endif 259 260 261/* 262 unsigned int FFI_HIDDEN 263 ffi_closure_SYSV_inner (closure, respp, args) 264 ffi_closure *closure; 265 void **respp; 266 void *args; 267*/ 268 269ARM_FUNC_START ffi_closure_SYSV 270 UNWIND .pad #16 271 add ip, sp, #16 272 stmfd sp!, {ip, lr} 273 UNWIND .save {r0, lr} 274 add r2, sp, #8 275 UNWIND .pad #16 276 sub sp, sp, #16 277 str sp, [sp, #8] 278 add r1, sp, #8 279 bl CNAME(ffi_closure_SYSV_inner) 280 cmp r0, #FFI_TYPE_INT 281 beq .Lretint 282 283 cmp r0, #FFI_TYPE_FLOAT 284#if defined(__SOFTFP__) || defined(__ARM_EABI__) 285 beq .Lretint 286#else 287 beq .Lretfloat 288#endif 289 290 cmp r0, #FFI_TYPE_DOUBLE 291#if defined(__SOFTFP__) || defined(__ARM_EABI__) 292 beq .Lretlonglong 293#else 294 beq .Lretdouble 295#endif 296 297 cmp r0, #FFI_TYPE_LONGDOUBLE 298#if defined(__SOFTFP__) || defined(__ARM_EABI__) 299 beq .Lretlonglong 300#else 301 beq .Lretlongdouble 302#endif 303 304 cmp r0, #FFI_TYPE_SINT64 305 beq .Lretlonglong 306.Lclosure_epilogue: 307 add sp, sp, #16 308 ldmfd sp, {sp, pc} 309.Lretint: 310 ldr r0, [sp] 311 b .Lclosure_epilogue 312.Lretlonglong: 313 ldr r0, [sp] 314 ldr r1, [sp, #4] 315 b .Lclosure_epilogue 316 317#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) 318.Lretfloat: 319 ldfs f0, [sp] 320 b .Lclosure_epilogue 321.Lretdouble: 322 ldfd f0, [sp] 323 b .Lclosure_epilogue 324.Lretlongdouble: 325 ldfd f0, [sp] 326 b .Lclosure_epilogue 327#endif 328 329.ffi_closure_SYSV_end: 330 UNWIND .fnend 331#ifdef __ELF__ 332 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) 333#endif 334 335 336/* Below are VFP hard-float ABI call and closure implementations. 337 Add VFP FPU directive here. This is only compiled into the library 338 under EABI. */ 339#ifdef __ARM_EABI__ 340 .fpu vfp 341 342 @ r0: fn 343 @ r1: &ecif 344 @ r2: cif->bytes 345 @ r3: fig->flags 346 @ sp+0: ecif.rvalue 347 348ARM_FUNC_START ffi_call_VFP 349 @ Save registers 350 stmfd sp!, {r0-r3, fp, lr} 351 UNWIND .save {r0-r3, fp, lr} 352 mov fp, sp 353 UNWIND .setfp fp, sp 354 355 @ Make room for all of the new args. 356 sub sp, sp, r2 357 358 @ Make room for loading VFP args 359 sub sp, sp, #64 360 361 @ Place all of the ffi_prep_args in position 362 mov r0, sp 363 @ r1 already set 364 sub r2, fp, #64 @ VFP scratch space 365 366 @ Call ffi_prep_args(stack, &ecif, vfp_space) 367 bl CNAME(ffi_prep_args) 368 369 @ Load VFP register args if needed 370 cmp r0, #0 371 beq LSYM(Lbase_args) 372 373 @ Load only d0 if possible 374 cmp r0, #3 375 sub ip, fp, #64 376 flddle d0, [ip] 377 fldmiadgt ip, {d0-d7} 378 379LSYM(Lbase_args): 380 @ move first 4 parameters in registers 381 ldmia sp, {r0-r3} 382 383 @ and adjust stack 384 sub lr, ip, sp @ cif->bytes == (fp - 64) - sp 385 ldr ip, [fp] @ load fn() in advance 386 cmp lr, #16 387 movhs lr, #16 388 add sp, sp, lr 389 390 @ call (fn) (...) 391 call_reg(ip) 392 393 @ Remove the space we pushed for the args 394 mov sp, fp 395 396 @ Load r2 with the pointer to storage for 397 @ the return value 398 ldr r2, [sp, #24] 399 400 @ Load r3 with the return type code 401 ldr r3, [sp, #12] 402 403 @ If the return value pointer is NULL, 404 @ assume no return value. 405 cmp r2, #0 406 beq LSYM(Lepilogue_vfp) 407 408 cmp r3, #FFI_TYPE_INT 409 streq r0, [r2] 410 beq LSYM(Lepilogue_vfp) 411 412 cmp r3, #FFI_TYPE_SINT64 413 stmeqia r2, {r0, r1} 414 beq LSYM(Lepilogue_vfp) 415 416 cmp r3, #FFI_TYPE_FLOAT 417 fstseq s0, [r2] 418 beq LSYM(Lepilogue_vfp) 419 420 cmp r3, #FFI_TYPE_DOUBLE 421 fstdeq d0, [r2] 422 beq LSYM(Lepilogue_vfp) 423 424 cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT 425 cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE 426 fstmiadeq r2, {d0-d3} 427 428LSYM(Lepilogue_vfp): 429 RETLDM "r0-r3,fp" 430 431.ffi_call_VFP_end: 432 UNWIND .fnend 433 .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP) 434 435 436ARM_FUNC_START ffi_closure_VFP 437 fstmfdd sp!, {d0-d7} 438 @ r0-r3, then d0-d7 439 UNWIND .pad #80 440 add ip, sp, #80 441 stmfd sp!, {ip, lr} 442 UNWIND .save {r0, lr} 443 add r2, sp, #72 444 add r3, sp, #8 445 UNWIND .pad #72 446 sub sp, sp, #72 447 str sp, [sp, #64] 448 add r1, sp, #64 449 bl CNAME(ffi_closure_SYSV_inner) 450 451 cmp r0, #FFI_TYPE_INT 452 beq .Lretint_vfp 453 454 cmp r0, #FFI_TYPE_FLOAT 455 beq .Lretfloat_vfp 456 457 cmp r0, #FFI_TYPE_DOUBLE 458 cmpne r0, #FFI_TYPE_LONGDOUBLE 459 beq .Lretdouble_vfp 460 461 cmp r0, #FFI_TYPE_SINT64 462 beq .Lretlonglong_vfp 463 464 cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT 465 beq .Lretfloat_struct_vfp 466 467 cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE 468 beq .Lretdouble_struct_vfp 469 470.Lclosure_epilogue_vfp: 471 add sp, sp, #72 472 ldmfd sp, {sp, pc} 473 474.Lretfloat_vfp: 475 flds s0, [sp] 476 b .Lclosure_epilogue_vfp 477.Lretdouble_vfp: 478 fldd d0, [sp] 479 b .Lclosure_epilogue_vfp 480.Lretint_vfp: 481 ldr r0, [sp] 482 b .Lclosure_epilogue_vfp 483.Lretlonglong_vfp: 484 ldmia sp, {r0, r1} 485 b .Lclosure_epilogue_vfp 486.Lretfloat_struct_vfp: 487 fldmiad sp, {d0-d1} 488 b .Lclosure_epilogue_vfp 489.Lretdouble_struct_vfp: 490 fldmiad sp, {d0-d3} 491 b .Lclosure_epilogue_vfp 492 493.ffi_closure_VFP_end: 494 UNWIND .fnend 495 .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP) 496#endif 497 498ENTRY(ffi_arm_trampoline) 499 stmfd sp!, {r0-r3} 500 ldr r0, [pc] 501 ldr pc, [pc] 502 503#if defined __ELF__ && defined __linux__ 504 .section .note.GNU-stack,"",%progbits 505#endif 506