Mercurial > hg > CbC > CbC_gcc
comparison libffi/src/metag/sysv.S @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
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] |