OSDN Git Service

90643185c7f94871e4e3db2e55d7ba185e0e5f26
[pf3gnuchains/gcc-fork.git] / libffi / 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:   ffi_prep_args
146         @ r1:   &ecif
147         @ r2:   cif->bytes
148         @ r3:   fig->flags
149         @ sp+0: ecif.rvalue
150         @ sp+4: fn
151
152         @ This assumes we are using gas.
153 ARM_FUNC_START ffi_call_SYSV
154         @ Save registers
155         stmfd   sp!, {r0-r3, fp, lr}
156         UNWIND .save    {r0-r3, fp, lr}
157         mov     fp, sp
158
159         UNWIND .setfp   fp, sp
160
161         @ Make room for all of the new args.
162         sub     sp, fp, r2
163
164         @ Place all of the ffi_prep_args in position
165         mov     ip, r0
166         mov     r0, sp
167         @     r1 already set
168
169         @ Call ffi_prep_args(stack, &ecif)
170         call_reg(ip)
171
172         @ move first 4 parameters in registers
173         ldmia   sp, {r0-r3}
174
175         @ and adjust stack
176         ldr     ip, [fp, #8]
177         cmp     ip, #16
178         movhs   ip, #16
179         add     sp, sp, ip
180
181         @ call (fn) (...)
182         ldr     ip, [fp, #28]
183         call_reg(ip)
184         
185         @ Remove the space we pushed for the args
186         mov     sp, fp
187
188         @ Load r2 with the pointer to storage for the return value
189         ldr     r2, [sp, #24]
190
191         @ Load r3 with the return type code 
192         ldr     r3, [sp, #12]
193
194         @ If the return value pointer is NULL, assume no return value.
195         cmp     r2, #0
196         beq     LSYM(Lepilogue)
197
198 @ return INT
199         cmp     r3, #FFI_TYPE_INT
200 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
201         cmpne   r3, #FFI_TYPE_FLOAT
202 #endif
203         streq   r0, [r2]
204         beq     LSYM(Lepilogue)
205
206         @ return INT64
207         cmp     r3, #FFI_TYPE_SINT64
208 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
209         cmpne   r3, #FFI_TYPE_DOUBLE
210 #endif
211         stmeqia r2, {r0, r1}
212
213 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
214         beq     LSYM(Lepilogue)
215
216 @ return FLOAT
217         cmp     r3, #FFI_TYPE_FLOAT
218         stfeqs  f0, [r2]
219         beq     LSYM(Lepilogue)
220
221 @ return DOUBLE or LONGDOUBLE
222         cmp     r3, #FFI_TYPE_DOUBLE
223         stfeqd  f0, [r2]
224 #endif
225
226 LSYM(Lepilogue):
227         RETLDM  "r0-r3,fp"
228
229 .ffi_call_SYSV_end:
230         UNWIND .fnend
231         .size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
232
233 /*
234         unsigned int FFI_HIDDEN
235         ffi_closure_SYSV_inner (closure, respp, args)
236              ffi_closure *closure;
237              void **respp;
238              void *args;
239 */
240
241 ARM_FUNC_START ffi_closure_SYSV
242         UNWIND .pad #16
243         add     ip, sp, #16
244         stmfd   sp!, {ip, lr}
245         UNWIND .save    {r0, lr}
246         add     r2, sp, #8
247         .pad #16
248         sub     sp, sp, #16
249         str     sp, [sp, #8]
250         add     r1, sp, #8
251         bl      ffi_closure_SYSV_inner
252         cmp     r0, #FFI_TYPE_INT
253         beq     .Lretint
254
255         cmp     r0, #FFI_TYPE_FLOAT
256 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
257         beq     .Lretint
258 #else
259         beq     .Lretfloat
260 #endif
261
262         cmp     r0, #FFI_TYPE_DOUBLE
263 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
264         beq     .Lretlonglong
265 #else
266         beq     .Lretdouble
267 #endif
268
269         cmp     r0, #FFI_TYPE_LONGDOUBLE
270 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
271         beq     .Lretlonglong
272 #else
273         beq     .Lretlongdouble
274 #endif
275
276         cmp     r0, #FFI_TYPE_SINT64
277         beq     .Lretlonglong
278 .Lclosure_epilogue:
279         add     sp, sp, #16
280         ldmfd   sp, {sp, pc}
281 .Lretint:
282         ldr     r0, [sp]
283         b       .Lclosure_epilogue
284 .Lretlonglong:
285         ldr     r0, [sp]
286         ldr     r1, [sp, #4]
287         b       .Lclosure_epilogue
288
289 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
290 .Lretfloat:
291         ldfs    f0, [sp]
292         b       .Lclosure_epilogue
293 .Lretdouble:
294         ldfd    f0, [sp]
295         b       .Lclosure_epilogue
296 .Lretlongdouble:
297         ldfd    f0, [sp]
298         b       .Lclosure_epilogue
299 #endif
300
301 .ffi_closure_SYSV_end:
302         UNWIND .fnend
303         .size    CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
304
305 #if defined __ELF__ && defined __linux__
306         .section        .note.GNU-stack,"",%progbits
307 #endif