Home | History | Annotate | Download | only in arm
      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