OSDN Git Service

Code drop from //branches/cupcake/...@124589
[android-x86/external-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__)
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