blob: 90643185c7f94871e4e3db2e55d7ba185e0e5f26 [file] [log] [blame]
Thomas Hellerd4c93202006-03-08 19:35:11 +00001/* -----------------------------------------------------------------------
Christian Heimes78644762008-03-04 23:39:23 +00002 sysv.S - Copyright (c) 1998, 2008 Red Hat, Inc.
Thomas Hellerd4c93202006-03-08 19:35:11 +00003
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
Christian Heimes78644762008-03-04 23:39:23 +000017 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.
Thomas Hellerd4c93202006-03-08 19:35:11 +000025 ----------------------------------------------------------------------- */
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__) \
Matthias Klosea8349752010-03-15 13:25:28 +000070 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
71 || defined(__ARM_ARCH_6M__)
Thomas Hellerd4c93202006-03-08 19:35:11 +000072# undef __ARM_ARCH__
73# define __ARM_ARCH__ 6
74#endif
75
Matthias Klosea8349752010-03-15 13:25:28 +000076#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
Thomas Hellerd4c93202006-03-08 19:35:11 +000083#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
Christian Heimes78644762008-03-04 23:39:23 +000094/* Conditionally compile unwinder directives. */
95#ifdef __ARM_EABI__
96#define UNWIND
97#else
98#define UNWIND @
99#endif
100
101
Thomas Hellerd4c93202006-03-08 19:35:11 +0000102#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
Christian Heimes78644762008-03-04 23:39:23 +0000112 UNWIND .fnstart
Thomas Hellerd4c93202006-03-08 19:35:11 +0000113/* 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)
Christian Heimes78644762008-03-04 23:39:23 +0000123 UNWIND .fnstart
Thomas Hellerd4c93202006-03-08 19:35:11 +0000124.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.
153ARM_FUNC_START ffi_call_SYSV
154 @ Save registers
155 stmfd sp!, {r0-r3, fp, lr}
Christian Heimes78644762008-03-04 23:39:23 +0000156 UNWIND .save {r0-r3, fp, lr}
Thomas Hellerd4c93202006-03-08 19:35:11 +0000157 mov fp, sp
158
Christian Heimes78644762008-03-04 23:39:23 +0000159 UNWIND .setfp fp, sp
160
Thomas Hellerd4c93202006-03-08 19:35:11 +0000161 @ 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
Matthias Klosea8349752010-03-15 13:25:28 +0000200#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000201 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
Matthias Klosea8349752010-03-15 13:25:28 +0000208#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000209 cmpne r3, #FFI_TYPE_DOUBLE
210#endif
211 stmeqia r2, {r0, r1}
212
Matthias Klosea8349752010-03-15 13:25:28 +0000213#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000214 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
226LSYM(Lepilogue):
227 RETLDM "r0-r3,fp"
228
229.ffi_call_SYSV_end:
Christian Heimes78644762008-03-04 23:39:23 +0000230 UNWIND .fnend
Thomas Hellerd4c93202006-03-08 19:35:11 +0000231 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
232
Christian Heimes78644762008-03-04 23:39:23 +0000233/*
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
241ARM_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
Matthias Klosea8349752010-03-15 13:25:28 +0000256#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000257 beq .Lretint
258#else
259 beq .Lretfloat
260#endif
261
262 cmp r0, #FFI_TYPE_DOUBLE
Matthias Klosea8349752010-03-15 13:25:28 +0000263#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000264 beq .Lretlonglong
265#else
266 beq .Lretdouble
267#endif
268
269 cmp r0, #FFI_TYPE_LONGDOUBLE
Matthias Klosea8349752010-03-15 13:25:28 +0000270#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000271 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
Matthias Klosea8349752010-03-15 13:25:28 +0000289#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000290.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