Home | History | Annotate | Download | only in arm
      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.
    159 ARM_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 
    231 LSYM(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 
    254 ARM_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 
    333 ARM_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 	fldmiadgt	ip, {d0-d7}
    364 
    365 LSYM(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 	stmeqia	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 	fstmiadeq	r2, {d0-d3}
    413 
    414 LSYM(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 
    422 ARM_FUNC_START(ffi_closure_VFP)
    423 	fstmfdd	sp!, {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 	fldmiad	sp, {d0-d1}
    474 	b	.Lclosure_epilogue_vfp
    475 .Lretdouble_struct_vfp:
    476 	fldmiad	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 
    484 ENTRY(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