OSDN Git Service

2009-10-10 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[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 # undef __ARM_ARCH__
79 # define __ARM_ARCH__ 7
80 #endif
81
82 #if __ARM_ARCH__ >= 5
83 # define call_reg(x)    blx     x
84 #elif defined (__ARM_ARCH_4T__)
85 # define call_reg(x)    mov     lr, pc ; bx     x
86 # if defined(__thumb__) || defined(__THUMB_INTERWORK__)
87 #  define __INTERWORKING__
88 # endif
89 #else
90 # define call_reg(x)    mov     lr, pc ; mov    pc, x
91 #endif
92
93 /* Conditionally compile unwinder directives.  */
94 #ifdef __ARM_EABI__
95 #define UNWIND
96 #else
97 #define UNWIND @
98 #endif  
99
100         
101 #if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
102 .macro  ARM_FUNC_START name
103         .text
104         .align 0
105         .thumb
106         .thumb_func
107         ENTRY(\name)
108         bx      pc
109         nop
110         .arm
111         UNWIND .fnstart
112 /* A hook to tell gdb that we've switched to ARM mode.  Also used to call
113    directly from other local arm routines.  */
114 _L__\name:              
115 .endm
116 #else
117 .macro  ARM_FUNC_START name
118         .text
119         .align 0
120         .arm
121         ENTRY(\name)
122         UNWIND .fnstart
123 .endm
124 #endif
125
126 .macro  RETLDM  regs=, cond=, dirn=ia
127 #if defined (__INTERWORKING__)
128         .ifc "\regs",""
129         ldr\cond        lr, [sp], #4
130         .else
131         ldm\cond\dirn   sp!, {\regs, lr}
132         .endif
133         bx\cond lr
134 #else
135         .ifc "\regs",""
136         ldr\cond        pc, [sp], #4
137         .else
138         ldm\cond\dirn   sp!, {\regs, pc}
139         .endif
140 #endif
141 .endm
142
143
144         @ r0:   ffi_prep_args
145         @ r1:   &ecif
146         @ r2:   cif->bytes
147         @ r3:   fig->flags
148         @ sp+0: ecif.rvalue
149         @ sp+4: fn
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     ip, r0
165         mov     r0, sp
166         @     r1 already set
167
168         @ Call ffi_prep_args(stack, &ecif)
169         call_reg(ip)
170
171         @ move first 4 parameters in registers
172         ldmia   sp, {r0-r3}
173
174         @ and adjust stack
175         ldr     ip, [fp, #8]
176         cmp     ip, #16
177         movhs   ip, #16
178         add     sp, sp, ip
179
180         @ call (fn) (...)
181         ldr     ip, [fp, #28]
182         call_reg(ip)
183         
184         @ Remove the space we pushed for the args
185         mov     sp, fp
186
187         @ Load r2 with the pointer to storage for the return value
188         ldr     r2, [sp, #24]
189
190         @ Load r3 with the return type code 
191         ldr     r3, [sp, #12]
192
193         @ If the return value pointer is NULL, assume no return value.
194         cmp     r2, #0
195         beq     LSYM(Lepilogue)
196
197 @ return INT
198         cmp     r3, #FFI_TYPE_INT
199 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
200         cmpne   r3, #FFI_TYPE_FLOAT
201 #endif
202         streq   r0, [r2]
203         beq     LSYM(Lepilogue)
204
205         @ return INT64
206         cmp     r3, #FFI_TYPE_SINT64
207 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
208         cmpne   r3, #FFI_TYPE_DOUBLE
209 #endif
210         stmeqia r2, {r0, r1}
211
212 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
213         beq     LSYM(Lepilogue)
214
215 @ return FLOAT
216         cmp     r3, #FFI_TYPE_FLOAT
217         stfeqs  f0, [r2]
218         beq     LSYM(Lepilogue)
219
220 @ return DOUBLE or LONGDOUBLE
221         cmp     r3, #FFI_TYPE_DOUBLE
222         stfeqd  f0, [r2]
223 #endif
224
225 LSYM(Lepilogue):
226         RETLDM  "r0-r3,fp"
227
228 .ffi_call_SYSV_end:
229         UNWIND .fnend
230         .size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
231
232 /*
233         unsigned int FFI_HIDDEN
234         ffi_closure_SYSV_inner (closure, respp, args)
235              ffi_closure *closure;
236              void **respp;
237              void *args;
238 */
239
240 ARM_FUNC_START ffi_closure_SYSV
241         UNWIND .pad #16
242         add     ip, sp, #16
243         stmfd   sp!, {ip, lr}
244         UNWIND .save    {r0, lr}
245         add     r2, sp, #8
246         .pad #16
247         sub     sp, sp, #16
248         str     sp, [sp, #8]
249         add     r1, sp, #8
250         bl      ffi_closure_SYSV_inner
251         cmp     r0, #FFI_TYPE_INT
252         beq     .Lretint
253
254         cmp     r0, #FFI_TYPE_FLOAT
255 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
256         beq     .Lretint
257 #else
258         beq     .Lretfloat
259 #endif
260
261         cmp     r0, #FFI_TYPE_DOUBLE
262 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
263         beq     .Lretlonglong
264 #else
265         beq     .Lretdouble
266 #endif
267
268         cmp     r0, #FFI_TYPE_LONGDOUBLE
269 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
270         beq     .Lretlonglong
271 #else
272         beq     .Lretlongdouble
273 #endif
274
275         cmp     r0, #FFI_TYPE_SINT64
276         beq     .Lretlonglong
277 .Lclosure_epilogue:
278         add     sp, sp, #16
279         ldmfd   sp, {sp, pc}
280 .Lretint:
281         ldr     r0, [sp]
282         b       .Lclosure_epilogue
283 .Lretlonglong:
284         ldr     r0, [sp]
285         ldr     r1, [sp, #4]
286         b       .Lclosure_epilogue
287
288 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
289 .Lretfloat:
290         ldfs    f0, [sp]
291         b       .Lclosure_epilogue
292 .Lretdouble:
293         ldfd    f0, [sp]
294         b       .Lclosure_epilogue
295 .Lretlongdouble:
296         ldfd    f0, [sp]
297         b       .Lclosure_epilogue
298 #endif
299
300 .ffi_closure_SYSV_end:
301         UNWIND .fnend
302         .size    CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
303
304 #if defined __ELF__ && defined __linux__
305         .section        .note.GNU-stack,"",%progbits
306 #endif