111
|
1 /* -----------------------------------------------------------------------
|
|
2 sysv.S - Copyright (c) 2013 Imagination Technologies Ltd.
|
|
3
|
|
4 Meta 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
|
|
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
|
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
25 DEALINGS IN THE SOFTWARE.
|
|
26 ----------------------------------------------------------------------- */
|
|
27
|
|
28 #define LIBFFI_ASM
|
|
29 #include <fficonfig.h>
|
|
30 #include <ffi.h>
|
|
31 #ifdef HAVE_MACHINE_ASM_H
|
|
32 #include <machine/asm.h>
|
|
33 #else
|
|
34 #ifdef __USER_LABEL_PREFIX__
|
|
35 #define CONCAT1(a, b) CONCAT2(a, b)
|
|
36 #define CONCAT2(a, b) a ## b
|
|
37
|
|
38 /* Use the right prefix for global labels. */
|
|
39 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
|
|
40 #else
|
|
41 #define CNAME(x) x
|
|
42 #endif
|
|
43 #define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x):
|
|
44 #endif
|
|
45
|
|
46 #ifdef __ELF__
|
|
47 #define LSYM(x) .x
|
|
48 #else
|
|
49 #define LSYM(x) x
|
|
50 #endif
|
|
51
|
|
52 .macro call_reg x=
|
|
53 .text
|
|
54 .balign 4
|
|
55 mov D1RtP, \x
|
|
56 swap D1RtP, PC
|
|
57 .endm
|
|
58
|
|
59 ! Save register arguments
|
|
60 .macro SAVE_ARGS
|
|
61 .text
|
|
62 .balign 4
|
|
63 setl [A0StP++], D0Ar6, D1Ar5
|
|
64 setl [A0StP++], D0Ar4, D1Ar3
|
|
65 setl [A0StP++], D0Ar2, D1Ar1
|
|
66 .endm
|
|
67
|
|
68 ! Save retrun, frame pointer and other regs
|
|
69 .macro SAVE_REGS regs=
|
|
70 .text
|
|
71 .balign 4
|
|
72 setl [A0StP++], D0FrT, D1RtP
|
|
73 ! Needs to be a pair of regs
|
|
74 .ifnc "\regs",""
|
|
75 setl [A0StP++], \regs
|
|
76 .endif
|
|
77 .endm
|
|
78
|
|
79 ! Declare a global function
|
|
80 .macro METAG_FUNC_START name
|
|
81 .text
|
|
82 .balign 4
|
|
83 ENTRY(\name)
|
|
84 .endm
|
|
85
|
|
86 ! Return registers from the stack. Reverse SAVE_REGS operation
|
|
87 .macro RET_REGS regs=, cond=
|
|
88 .ifnc "\regs", ""
|
|
89 getl \regs, [--A0StP]
|
|
90 .endif
|
|
91 getl D0FrT, D1RtP, [--A0StP]
|
|
92 .endm
|
|
93
|
|
94 ! Return arguments
|
|
95 .macro RET_ARGS
|
|
96 getl D0Ar2, D1Ar1, [--A0StP]
|
|
97 getl D0Ar4, D1Ar3, [--A0StP]
|
|
98 getl D0Ar6, D1Ar5, [--A0StP]
|
|
99 .endm
|
|
100
|
|
101
|
|
102 ! D1Ar1: fn
|
|
103 ! D0Ar2: &ecif
|
|
104 ! D1Ar3: cif->bytes
|
|
105 ! D0Ar4: fig->flags
|
|
106 ! D1Ar5: ecif.rvalue
|
|
107
|
|
108 ! This assumes we are using GNU as
|
|
109 METAG_FUNC_START ffi_call_SYSV
|
|
110 ! Save argument registers
|
|
111
|
|
112 SAVE_ARGS
|
|
113
|
|
114 ! new frame
|
|
115 mov D0FrT, A0FrP
|
|
116 add A0FrP, A0StP, #0
|
|
117
|
|
118 ! Preserve the old frame pointer
|
|
119 SAVE_REGS "D1.5, D0.5"
|
|
120
|
|
121 ! Make room for new args. cifs->bytes is the total space for input
|
|
122 ! and return arguments
|
|
123
|
|
124 add A0StP, A0StP, D1Ar3
|
|
125
|
|
126 ! Preserve cifs->bytes & fn
|
|
127 mov D0.5, D1Ar3
|
|
128 mov D1.5, D1Ar1
|
|
129
|
|
130 ! Place all of the ffi_prep_args in position
|
|
131 mov D1Ar1, A0StP
|
|
132
|
|
133 ! Call ffi_prep_args(stack, &ecif)
|
|
134 #ifdef __PIC__
|
|
135 callr D1RtP, CNAME(ffi_prep_args@PLT)
|
|
136 #else
|
|
137 callr D1RtP, CNAME(ffi_prep_args)
|
|
138 #endif
|
|
139
|
|
140 ! Restore fn pointer
|
|
141
|
|
142 ! The foreign stack should look like this
|
|
143 ! XXXXX XXXXXX <--- stack pointer
|
|
144 ! FnArgN rvalue
|
|
145 ! FnArgN+2 FnArgN+1
|
|
146 ! FnArgN+4 FnArgN+3
|
|
147 ! ....
|
|
148 !
|
|
149
|
|
150 ! A0StP now points to the first (or return) argument + 4
|
|
151
|
|
152 ! Preserve cif->bytes
|
|
153 getl D0Ar2, D1Ar1, [--A0StP]
|
|
154 getl D0Ar4, D1Ar3, [--A0StP]
|
|
155 getl D0Ar6, D1Ar5, [--A0StP]
|
|
156
|
|
157 ! Place A0StP to the first argument again
|
|
158 add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each
|
|
159
|
|
160 ! A0FrP points to the initial stack without the reserved space for the
|
|
161 ! cifs->bytes, whilst A0StP points to the stack after the space allocation
|
|
162
|
|
163 ! fn was the first argument of ffi_call_SYSV.
|
|
164 ! The stack at this point looks like this:
|
|
165 !
|
|
166 ! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low
|
|
167 ! Arg4 Arg3 |
|
|
168 ! Arg2 Arg1 |
|
|
169 ! A0FrP ----> D0FrtP D1RtP |
|
|
170 ! D1.5 D0.5 |
|
|
171 ! A0StP(bf prep_args) -> FnArgn FnArgn-1 |
|
|
172 ! FnArgn-2FnArgn-3 |
|
|
173 ! ................ | <= cifs->bytes
|
|
174 ! FnArg4 FnArg3 |
|
|
175 ! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high
|
|
176 !
|
|
177 ! fn was in Arg1 so it's located in in A0FrP+#-0xC
|
|
178 !
|
|
179
|
|
180 ! D0Re0 contains the size of arguments stored in registers
|
|
181 sub A0StP, A0StP, D0Re0
|
|
182
|
|
183 ! Arg1 is the function pointer for the foreign call. This has been
|
|
184 ! preserved in D1.5
|
|
185
|
|
186 ! Time to call (fn). Arguments should be like this:
|
|
187 ! Arg1-Arg6 are loaded to regs
|
|
188 ! The rest of the arguments are stored in stack pointed by A0StP
|
|
189
|
|
190 call_reg D1.5
|
|
191
|
|
192 ! Reset stack.
|
|
193
|
|
194 mov A0StP, A0FrP
|
|
195
|
|
196 ! Load Arg1 with the pointer to storage for the return type
|
|
197 ! This was stored in Arg5
|
|
198
|
|
199 getd D1Ar1, [A0FrP+#-20]
|
|
200
|
|
201 ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags)
|
|
202
|
|
203 getd D0Ar2, [A0FrP+#-16]
|
|
204
|
|
205 ! We are ready to start processing the return value
|
|
206 ! D0Re0 (and D1Re0) hold the return value
|
|
207
|
|
208 ! If the return value is NULL, assume no return value
|
|
209 cmp D1Ar1, #0
|
|
210 beq LSYM(Lepilogue)
|
|
211
|
|
212 ! return INT
|
|
213 cmp D0Ar2, #FFI_TYPE_INT
|
|
214 ! Sadly, there is no setd{cc} instruction so we need to workaround that
|
|
215 bne .INT64
|
|
216 setd [D1Ar1], D0Re0
|
|
217 b LSYM(Lepilogue)
|
|
218
|
|
219 ! return INT64
|
|
220 .INT64:
|
|
221 cmp D0Ar2, #FFI_TYPE_SINT64
|
|
222 setleq [D1Ar1], D0Re0, D1Re0
|
|
223
|
|
224 ! return DOUBLE
|
|
225 cmp D0Ar2, #FFI_TYPE_DOUBLE
|
|
226 setl [D1AR1++], D0Re0, D1Re0
|
|
227
|
|
228 LSYM(Lepilogue):
|
|
229 ! At this point, the stack pointer points right after the argument
|
|
230 ! saved area. We need to restore 4 regs, therefore we need to move
|
|
231 ! 16 bytes ahead.
|
|
232 add A0StP, A0StP, #16
|
|
233 RET_REGS "D1.5, D0.5"
|
|
234 RET_ARGS
|
|
235 getd D0Re0, [A0StP]
|
|
236 mov A0FrP, D0FrT
|
|
237 swap D1RtP, PC
|
|
238
|
|
239 .ffi_call_SYSV_end:
|
|
240 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
|
241
|
|
242
|
|
243 /*
|
|
244 (called by ffi_metag_trampoline)
|
|
245 void ffi_closure_SYSV (ffi_closure*)
|
|
246
|
|
247 (called by ffi_closure_SYSV)
|
|
248 unsigned int FFI_HIDDEN
|
|
249 ffi_closure_SYSV_inner (closure,respp, args)
|
|
250 ffi_closure *closure;
|
|
251 void **respp;
|
|
252 void *args;
|
|
253 */
|
|
254
|
|
255 METAG_FUNC_START ffi_closure_SYSV
|
|
256 ! We assume that D1Ar1 holds the address of the
|
|
257 ! ffi_closure struct. We will use that to fetch the
|
|
258 ! arguments. The stack pointer points to an empty space
|
|
259 ! and it is ready to store more data.
|
|
260
|
|
261 ! D1Ar1 is ready
|
|
262 ! Allocate stack space for return value
|
|
263 add A0StP, A0StP, #8
|
|
264 ! Store it to D0Ar2
|
|
265 sub D0Ar2, A0StP, #8
|
|
266
|
|
267 sub D1Ar3, A0FrP, #4
|
|
268
|
|
269 ! D1Ar3 contains the address of the original D1Ar1 argument
|
|
270 ! We need to subtract #4 later on
|
|
271
|
|
272 ! Preverve D0Ar2
|
|
273 mov D0.5, D0Ar2
|
|
274
|
|
275 #ifdef __PIC__
|
|
276 callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT)
|
|
277 #else
|
|
278 callr D1RtP, CNAME(ffi_closure_SYSV_inner)
|
|
279 #endif
|
|
280
|
|
281 ! Check the return value and store it to D0.5
|
|
282 cmp D0Re0, #FFI_TYPE_INT
|
|
283 beq .Lretint
|
|
284 cmp D0Re0, #FFI_TYPE_DOUBLE
|
|
285 beq .Lretdouble
|
|
286 .Lclosure_epilogue:
|
|
287 sub A0StP, A0StP, #8
|
|
288 RET_REGS "D1.5, D0.5"
|
|
289 RET_ARGS
|
|
290 swap D1RtP, PC
|
|
291
|
|
292 .Lretint:
|
|
293 setd [D0.5], D0Re0
|
|
294 b .Lclosure_epilogue
|
|
295 .Lretdouble:
|
|
296 setl [D0.5++], D0Re0, D1Re0
|
|
297 b .Lclosure_epilogue
|
|
298 .ffi_closure_SYSV_end:
|
|
299 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
|
|
300
|
|
301
|
|
302 ENTRY(ffi_metag_trampoline)
|
|
303 SAVE_ARGS
|
|
304 ! New frame
|
|
305 mov A0FrP, A0StP
|
|
306 SAVE_REGS "D1.5, D0.5"
|
|
307 mov D0.5, PC
|
|
308 ! Load D1Ar1 the value of ffi_metag_trampoline
|
|
309 getd D1Ar1, [D0.5 + #8]
|
|
310 ! Jump to ffi_closure_SYSV
|
|
311 getd PC, [D0.5 + #12]
|