OSDN Git Service

Compile in support for closures
[android-x86/external-libffi.git] / src / arm / sysv.S
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         vldmiagt        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         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
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         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
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