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