1; -----------------------------------------------------------------------
2;  sysv.S - Copyright (c) 1998 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, EXPRESS
18;  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19;  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20;  IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21;  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22;  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23;  OTHER DEALINGS IN THE SOFTWARE.
24;  ----------------------------------------------------------------------- */
25
26;#define LIBFFI_ASM
27;#include <fficonfig.h>
28;#include <ffi.h>
29;#ifdef HAVE_MACHINE_ASM_H
30;#include <machine/asm.h>
31;#else
32;#ifdef __USER_LABEL_PREFIX__
33;#define CONCAT1(a, b) CONCAT2(a, b)
34;#define CONCAT2(a, b) a ## b
35
36;/* Use the right prefix for global labels.  */
37;#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
38;#else
39;#define CNAME(x) x
40;#endif
41;#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
42;#endif
43
44
45FFI_TYPE_VOID       EQU 0
46FFI_TYPE_INT        EQU 1
47FFI_TYPE_FLOAT      EQU 2
48FFI_TYPE_DOUBLE     EQU 3
49;FFI_TYPE_LONGDOUBLE EQU 4
50FFI_TYPE_UINT8      EQU 5
51FFI_TYPE_SINT8      EQU 6
52FFI_TYPE_UINT16     EQU 7
53FFI_TYPE_SINT16     EQU 8
54FFI_TYPE_UINT32     EQU 9
55FFI_TYPE_SINT32     EQU 10
56FFI_TYPE_UINT64     EQU 11
57FFI_TYPE_SINT64     EQU 12
58FFI_TYPE_STRUCT     EQU 13
59FFI_TYPE_POINTER    EQU 14
60
61; WinCE always uses software floating point (I think)
62__SOFTFP__ EQU {TRUE}
63
64
65    AREA |.text|, CODE, ARM     ; .text
66
67
68    ; a1:   ffi_prep_args
69    ; a2:   &ecif
70    ; a3:   cif->bytes
71    ; a4:   fig->flags
72    ; sp+0: ecif.rvalue
73    ; sp+4: fn
74
75    ; This assumes we are using gas.
76;ENTRY(ffi_call_SYSV)
77
78    EXPORT |ffi_call_SYSV|
79
80|ffi_call_SYSV| PROC
81
82    ; Save registers
83    stmfd sp!, {a1-a4, fp, lr}
84    mov   fp, sp
85
86    ; Make room for all of the new args.
87    sub   sp, fp, a3
88
89    ; Place all of the ffi_prep_args in position
90    mov   ip, a1
91    mov   a1, sp
92    ;     a2 already set
93
94    ; And call
95    mov   lr, pc
96    mov   pc, ip
97
98    ; move first 4 parameters in registers
99    ldr   a1, [sp, #0]
100    ldr   a2, [sp, #4]
101    ldr   a3, [sp, #8]
102    ldr   a4, [sp, #12]
103
104    ; and adjust stack
105    ldr   ip, [fp, #8]
106    cmp   ip, #16
107    movge ip, #16
108    add   sp, sp, ip
109
110    ; call function
111    mov   lr, pc
112    ldr   pc, [fp, #28]
113
114    ; Remove the space we pushed for the args
115    mov   sp, fp
116
117    ; Load a3 with the pointer to storage for the return value
118    ldr   a3, [sp, #24]
119
120    ; Load a4 with the return type code
121    ldr   a4, [sp, #12]
122
123    ; If the return value pointer is NULL, assume no return value.
124    cmp   a3, #0
125    beq   call_epilogue
126
127; return INT
128    cmp   a4, #FFI_TYPE_INT
129    streq a1, [a3]
130    beq   call_epilogue
131
132; return FLOAT
133    cmp     a4, #FFI_TYPE_FLOAT
134    [ __SOFTFP__                    ;ifdef __SOFTFP__
135    streq   a1, [a3]
136    |                               ;else
137    stfeqs  f0, [a3]
138    ]                               ;endif
139    beq     call_epilogue
140
141; return DOUBLE or LONGDOUBLE
142    cmp     a4, #FFI_TYPE_DOUBLE
143    [ __SOFTFP__                    ;ifdef __SOFTFP__
144    stmeqia a3, {a1, a2}
145    |                               ;else
146    stfeqd  f0, [a3]
147    ]                               ;endif
148    beq     call_epilogue
149
150; return SINT64 or UINT64
151    cmp     a4, #FFI_TYPE_SINT64
152    stmeqia a3, {a1, a2}
153
154call_epilogue
155    ldmfd   sp!, {a1-a4, fp, pc}
156
157;.ffi_call_SYSV_end:
158    ;.size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
159    ENDP
160
161
162RESERVE_RETURN EQU 16
163
164    ; This function is called by the trampoline
165    ; It is NOT callable from C
166    ; ip = pointer to struct ffi_closure
167
168    IMPORT |ffi_closure_SYSV_inner|
169
170    EXPORT |ffi_closure_SYSV|
171|ffi_closure_SYSV| PROC
172
173    ; Store the argument registers on the stack
174    stmfd   sp!, {a1-a4}
175    ; Push the return address onto the stack
176    stmfd   sp!, {lr}
177
178    mov     a1, ip            ; first arg = address of ffi_closure
179    add     a2, sp, #4        ; second arg = sp+4 (points to saved a1)
180
181    ; Allocate space for a non-struct return value
182    sub     sp, sp, #RESERVE_RETURN
183    mov     a3, sp            ; third arg = return value address
184
185    ; static unsigned int
186    ; ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue)
187    bl      ffi_closure_SYSV_inner
188    ; a1 now contains the return type code
189
190    ; At this point the return value is on the stack
191    ; Transfer it to the correct registers if necessary
192
193; return INT
194    cmp     a1, #FFI_TYPE_INT
195    ldreq   a1, [sp]
196    beq     closure_epilogue
197
198; return FLOAT
199    cmp     a1, #FFI_TYPE_FLOAT
200    [ __SOFTFP__                    ;ifdef __SOFTFP__
201    ldreq   a1, [sp]
202    |                               ;else
203    stfeqs  f0, [sp]
204    ]                               ;endif
205    beq     closure_epilogue
206
207; return DOUBLE or LONGDOUBLE
208    cmp     a1, #FFI_TYPE_DOUBLE
209    [ __SOFTFP__                    ;ifdef __SOFTFP__
210    ldmeqia sp, {a1, a2}
211    |                               ;else
212    stfeqd  f0, [sp]
213    ]                               ;endif
214    beq     closure_epilogue
215
216; return SINT64 or UINT64
217    cmp     a1, #FFI_TYPE_SINT64
218    ldmeqia sp, {a1, a2}
219
220closure_epilogue
221    add     sp, sp, #RESERVE_RETURN   ; remove return value buffer
222    ldmfd   sp!, {ip}         ; ip = pop return address
223    add     sp, sp, #16       ; remove saved argument registers {a1-a4} from the stack
224    mov     pc, ip            ; return
225
226    ENDP    ; ffi_closure_SYSV
227
228    END
229