annotate libffi/src/sh/ffi.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 04ced10e8804
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* -----------------------------------------------------------------------
kono
parents:
diff changeset
2 ffi.c - Copyright (c) 2002-2008, 2012 Kaz Kojima
kono
parents:
diff changeset
3 Copyright (c) 2008 Red Hat, Inc.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 SuperH Foreign Function Interface
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 Permission is hereby granted, free of charge, to any person obtaining
kono
parents:
diff changeset
8 a copy of this software and associated documentation files (the
kono
parents:
diff changeset
9 ``Software''), to deal in the Software without restriction, including
kono
parents:
diff changeset
10 without limitation the rights to use, copy, modify, merge, publish,
kono
parents:
diff changeset
11 distribute, sublicense, and/or sell copies of the Software, and to
kono
parents:
diff changeset
12 permit persons to whom the Software is furnished to do so, subject to
kono
parents:
diff changeset
13 the following conditions:
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 The above copyright notice and this permission notice shall be included
kono
parents:
diff changeset
16 in all copies or substantial portions of the Software.
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
kono
parents:
diff changeset
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
kono
parents:
diff changeset
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
kono
parents:
diff changeset
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
kono
parents:
diff changeset
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
kono
parents:
diff changeset
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kono
parents:
diff changeset
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
kono
parents:
diff changeset
25 DEALINGS IN THE SOFTWARE.
kono
parents:
diff changeset
26 ----------------------------------------------------------------------- */
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 #include <ffi.h>
kono
parents:
diff changeset
29 #include <ffi_common.h>
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 #include <stdlib.h>
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 #define NGREGARG 4
kono
parents:
diff changeset
34 #if defined(__SH4__)
kono
parents:
diff changeset
35 #define NFREGARG 8
kono
parents:
diff changeset
36 #endif
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 #if defined(__HITACHI__)
kono
parents:
diff changeset
39 #define STRUCT_VALUE_ADDRESS_WITH_ARG 1
kono
parents:
diff changeset
40 #else
kono
parents:
diff changeset
41 #define STRUCT_VALUE_ADDRESS_WITH_ARG 0
kono
parents:
diff changeset
42 #endif
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 /* If the structure has essentially an unique element, return its type. */
kono
parents:
diff changeset
45 static int
kono
parents:
diff changeset
46 simple_type (ffi_type *arg)
kono
parents:
diff changeset
47 {
kono
parents:
diff changeset
48 if (arg->type != FFI_TYPE_STRUCT)
kono
parents:
diff changeset
49 return arg->type;
kono
parents:
diff changeset
50 else if (arg->elements[1])
kono
parents:
diff changeset
51 return FFI_TYPE_STRUCT;
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53 return simple_type (arg->elements[0]);
kono
parents:
diff changeset
54 }
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 static int
kono
parents:
diff changeset
57 return_type (ffi_type *arg)
kono
parents:
diff changeset
58 {
kono
parents:
diff changeset
59 unsigned short type;
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 if (arg->type != FFI_TYPE_STRUCT)
kono
parents:
diff changeset
62 return arg->type;
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 type = simple_type (arg->elements[0]);
kono
parents:
diff changeset
65 if (! arg->elements[1])
kono
parents:
diff changeset
66 {
kono
parents:
diff changeset
67 switch (type)
kono
parents:
diff changeset
68 {
kono
parents:
diff changeset
69 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
70 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
71 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
72 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
73 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
74 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
75 return FFI_TYPE_INT;
kono
parents:
diff changeset
76
kono
parents:
diff changeset
77 default:
kono
parents:
diff changeset
78 return type;
kono
parents:
diff changeset
79 }
kono
parents:
diff changeset
80 }
kono
parents:
diff changeset
81
kono
parents:
diff changeset
82 /* gcc uses r0/r1 pair for some kind of structures. */
kono
parents:
diff changeset
83 if (arg->size <= 2 * sizeof (int))
kono
parents:
diff changeset
84 {
kono
parents:
diff changeset
85 int i = 0;
kono
parents:
diff changeset
86 ffi_type *e;
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 while ((e = arg->elements[i++]))
kono
parents:
diff changeset
89 {
kono
parents:
diff changeset
90 type = simple_type (e);
kono
parents:
diff changeset
91 switch (type)
kono
parents:
diff changeset
92 {
kono
parents:
diff changeset
93 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
94 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
95 case FFI_TYPE_INT:
kono
parents:
diff changeset
96 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
97 return FFI_TYPE_UINT64;
kono
parents:
diff changeset
98
kono
parents:
diff changeset
99 default:
kono
parents:
diff changeset
100 break;
kono
parents:
diff changeset
101 }
kono
parents:
diff changeset
102 }
kono
parents:
diff changeset
103 }
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 return FFI_TYPE_STRUCT;
kono
parents:
diff changeset
106 }
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 /* ffi_prep_args is called by the assembly routine once stack space
kono
parents:
diff changeset
109 has been allocated for the function's arguments */
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 void ffi_prep_args(char *stack, extended_cif *ecif)
kono
parents:
diff changeset
112 {
kono
parents:
diff changeset
113 register unsigned int i;
kono
parents:
diff changeset
114 register int tmp;
kono
parents:
diff changeset
115 register unsigned int avn;
kono
parents:
diff changeset
116 register void **p_argv;
kono
parents:
diff changeset
117 register char *argp;
kono
parents:
diff changeset
118 register ffi_type **p_arg;
kono
parents:
diff changeset
119 int greg, ireg;
kono
parents:
diff changeset
120 #if defined(__SH4__)
kono
parents:
diff changeset
121 int freg = 0;
kono
parents:
diff changeset
122 #endif
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 tmp = 0;
kono
parents:
diff changeset
125 argp = stack;
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
kono
parents:
diff changeset
128 {
kono
parents:
diff changeset
129 *(void **) argp = ecif->rvalue;
kono
parents:
diff changeset
130 argp += 4;
kono
parents:
diff changeset
131 ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
kono
parents:
diff changeset
132 }
kono
parents:
diff changeset
133 else
kono
parents:
diff changeset
134 ireg = 0;
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 /* Set arguments for registers. */
kono
parents:
diff changeset
137 greg = ireg;
kono
parents:
diff changeset
138 avn = ecif->cif->nargs;
kono
parents:
diff changeset
139 p_argv = ecif->avalue;
kono
parents:
diff changeset
140
kono
parents:
diff changeset
141 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
kono
parents:
diff changeset
142 {
kono
parents:
diff changeset
143 size_t z;
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 z = (*p_arg)->size;
kono
parents:
diff changeset
146 if (z < sizeof(int))
kono
parents:
diff changeset
147 {
kono
parents:
diff changeset
148 if (greg++ >= NGREGARG)
kono
parents:
diff changeset
149 continue;
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 z = sizeof(int);
kono
parents:
diff changeset
152 switch ((*p_arg)->type)
kono
parents:
diff changeset
153 {
kono
parents:
diff changeset
154 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
155 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
kono
parents:
diff changeset
156 break;
kono
parents:
diff changeset
157
kono
parents:
diff changeset
158 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
159 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
kono
parents:
diff changeset
160 break;
kono
parents:
diff changeset
161
kono
parents:
diff changeset
162 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
163 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
kono
parents:
diff changeset
164 break;
kono
parents:
diff changeset
165
kono
parents:
diff changeset
166 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
167 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
kono
parents:
diff changeset
168 break;
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
171 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
kono
parents:
diff changeset
172 break;
kono
parents:
diff changeset
173
kono
parents:
diff changeset
174 default:
kono
parents:
diff changeset
175 FFI_ASSERT(0);
kono
parents:
diff changeset
176 }
kono
parents:
diff changeset
177 argp += z;
kono
parents:
diff changeset
178 }
kono
parents:
diff changeset
179 else if (z == sizeof(int))
kono
parents:
diff changeset
180 {
kono
parents:
diff changeset
181 #if defined(__SH4__)
kono
parents:
diff changeset
182 if ((*p_arg)->type == FFI_TYPE_FLOAT)
kono
parents:
diff changeset
183 {
kono
parents:
diff changeset
184 if (freg++ >= NFREGARG)
kono
parents:
diff changeset
185 continue;
kono
parents:
diff changeset
186 }
kono
parents:
diff changeset
187 else
kono
parents:
diff changeset
188 #endif
kono
parents:
diff changeset
189 {
kono
parents:
diff changeset
190 if (greg++ >= NGREGARG)
kono
parents:
diff changeset
191 continue;
kono
parents:
diff changeset
192 }
kono
parents:
diff changeset
193 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
kono
parents:
diff changeset
194 argp += z;
kono
parents:
diff changeset
195 }
kono
parents:
diff changeset
196 #if defined(__SH4__)
kono
parents:
diff changeset
197 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
kono
parents:
diff changeset
198 {
kono
parents:
diff changeset
199 if (freg + 1 >= NFREGARG)
kono
parents:
diff changeset
200 continue;
kono
parents:
diff changeset
201 freg = (freg + 1) & ~1;
kono
parents:
diff changeset
202 freg += 2;
kono
parents:
diff changeset
203 memcpy (argp, *p_argv, z);
kono
parents:
diff changeset
204 argp += z;
kono
parents:
diff changeset
205 }
kono
parents:
diff changeset
206 #endif
kono
parents:
diff changeset
207 else
kono
parents:
diff changeset
208 {
kono
parents:
diff changeset
209 int n = (z + sizeof (int) - 1) / sizeof (int);
kono
parents:
diff changeset
210 #if defined(__SH4__)
kono
parents:
diff changeset
211 if (greg + n - 1 >= NGREGARG)
kono
parents:
diff changeset
212 continue;
kono
parents:
diff changeset
213 #else
kono
parents:
diff changeset
214 if (greg >= NGREGARG)
kono
parents:
diff changeset
215 continue;
kono
parents:
diff changeset
216 #endif
kono
parents:
diff changeset
217 greg += n;
kono
parents:
diff changeset
218 memcpy (argp, *p_argv, z);
kono
parents:
diff changeset
219 argp += n * sizeof (int);
kono
parents:
diff changeset
220 }
kono
parents:
diff changeset
221 }
kono
parents:
diff changeset
222
kono
parents:
diff changeset
223 /* Set arguments on stack. */
kono
parents:
diff changeset
224 greg = ireg;
kono
parents:
diff changeset
225 #if defined(__SH4__)
kono
parents:
diff changeset
226 freg = 0;
kono
parents:
diff changeset
227 #endif
kono
parents:
diff changeset
228 p_argv = ecif->avalue;
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
kono
parents:
diff changeset
231 {
kono
parents:
diff changeset
232 size_t z;
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 z = (*p_arg)->size;
kono
parents:
diff changeset
235 if (z < sizeof(int))
kono
parents:
diff changeset
236 {
kono
parents:
diff changeset
237 if (greg++ < NGREGARG)
kono
parents:
diff changeset
238 continue;
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 z = sizeof(int);
kono
parents:
diff changeset
241 switch ((*p_arg)->type)
kono
parents:
diff changeset
242 {
kono
parents:
diff changeset
243 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
244 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
kono
parents:
diff changeset
245 break;
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
248 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
kono
parents:
diff changeset
249 break;
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
252 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
kono
parents:
diff changeset
253 break;
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
256 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
kono
parents:
diff changeset
257 break;
kono
parents:
diff changeset
258
kono
parents:
diff changeset
259 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
260 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
kono
parents:
diff changeset
261 break;
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263 default:
kono
parents:
diff changeset
264 FFI_ASSERT(0);
kono
parents:
diff changeset
265 }
kono
parents:
diff changeset
266 argp += z;
kono
parents:
diff changeset
267 }
kono
parents:
diff changeset
268 else if (z == sizeof(int))
kono
parents:
diff changeset
269 {
kono
parents:
diff changeset
270 #if defined(__SH4__)
kono
parents:
diff changeset
271 if ((*p_arg)->type == FFI_TYPE_FLOAT)
kono
parents:
diff changeset
272 {
kono
parents:
diff changeset
273 if (freg++ < NFREGARG)
kono
parents:
diff changeset
274 continue;
kono
parents:
diff changeset
275 }
kono
parents:
diff changeset
276 else
kono
parents:
diff changeset
277 #endif
kono
parents:
diff changeset
278 {
kono
parents:
diff changeset
279 if (greg++ < NGREGARG)
kono
parents:
diff changeset
280 continue;
kono
parents:
diff changeset
281 }
kono
parents:
diff changeset
282 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
kono
parents:
diff changeset
283 argp += z;
kono
parents:
diff changeset
284 }
kono
parents:
diff changeset
285 #if defined(__SH4__)
kono
parents:
diff changeset
286 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
kono
parents:
diff changeset
287 {
kono
parents:
diff changeset
288 if (freg + 1 < NFREGARG)
kono
parents:
diff changeset
289 {
kono
parents:
diff changeset
290 freg = (freg + 1) & ~1;
kono
parents:
diff changeset
291 freg += 2;
kono
parents:
diff changeset
292 continue;
kono
parents:
diff changeset
293 }
kono
parents:
diff changeset
294 memcpy (argp, *p_argv, z);
kono
parents:
diff changeset
295 argp += z;
kono
parents:
diff changeset
296 }
kono
parents:
diff changeset
297 #endif
kono
parents:
diff changeset
298 else
kono
parents:
diff changeset
299 {
kono
parents:
diff changeset
300 int n = (z + sizeof (int) - 1) / sizeof (int);
kono
parents:
diff changeset
301 if (greg + n - 1 < NGREGARG)
kono
parents:
diff changeset
302 {
kono
parents:
diff changeset
303 greg += n;
kono
parents:
diff changeset
304 continue;
kono
parents:
diff changeset
305 }
kono
parents:
diff changeset
306 #if (! defined(__SH4__))
kono
parents:
diff changeset
307 else if (greg < NGREGARG)
kono
parents:
diff changeset
308 {
kono
parents:
diff changeset
309 greg = NGREGARG;
kono
parents:
diff changeset
310 continue;
kono
parents:
diff changeset
311 }
kono
parents:
diff changeset
312 #endif
kono
parents:
diff changeset
313 memcpy (argp, *p_argv, z);
kono
parents:
diff changeset
314 argp += n * sizeof (int);
kono
parents:
diff changeset
315 }
kono
parents:
diff changeset
316 }
kono
parents:
diff changeset
317
kono
parents:
diff changeset
318 return;
kono
parents:
diff changeset
319 }
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 /* Perform machine dependent cif processing */
kono
parents:
diff changeset
322 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
kono
parents:
diff changeset
323 {
kono
parents:
diff changeset
324 int i, j;
kono
parents:
diff changeset
325 int size, type;
kono
parents:
diff changeset
326 int n, m;
kono
parents:
diff changeset
327 int greg;
kono
parents:
diff changeset
328 #if defined(__SH4__)
kono
parents:
diff changeset
329 int freg = 0;
kono
parents:
diff changeset
330 #endif
kono
parents:
diff changeset
331
kono
parents:
diff changeset
332 cif->flags = 0;
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
kono
parents:
diff changeset
335 STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 #if defined(__SH4__)
kono
parents:
diff changeset
338 for (i = j = 0; i < cif->nargs && j < 12; i++)
kono
parents:
diff changeset
339 {
kono
parents:
diff changeset
340 type = (cif->arg_types)[i]->type;
kono
parents:
diff changeset
341 switch (type)
kono
parents:
diff changeset
342 {
kono
parents:
diff changeset
343 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
344 if (freg >= NFREGARG)
kono
parents:
diff changeset
345 continue;
kono
parents:
diff changeset
346 freg++;
kono
parents:
diff changeset
347 cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
kono
parents:
diff changeset
348 j++;
kono
parents:
diff changeset
349 break;
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
352 if ((freg + 1) >= NFREGARG)
kono
parents:
diff changeset
353 continue;
kono
parents:
diff changeset
354 freg = (freg + 1) & ~1;
kono
parents:
diff changeset
355 freg += 2;
kono
parents:
diff changeset
356 cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
kono
parents:
diff changeset
357 j++;
kono
parents:
diff changeset
358 break;
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 default:
kono
parents:
diff changeset
361 size = (cif->arg_types)[i]->size;
kono
parents:
diff changeset
362 n = (size + sizeof (int) - 1) / sizeof (int);
kono
parents:
diff changeset
363 if (greg + n - 1 >= NGREGARG)
kono
parents:
diff changeset
364 continue;
kono
parents:
diff changeset
365 greg += n;
kono
parents:
diff changeset
366 for (m = 0; m < n; m++)
kono
parents:
diff changeset
367 cif->flags += FFI_TYPE_INT << (2 * j++);
kono
parents:
diff changeset
368 break;
kono
parents:
diff changeset
369 }
kono
parents:
diff changeset
370 }
kono
parents:
diff changeset
371 #else
kono
parents:
diff changeset
372 for (i = j = 0; i < cif->nargs && j < 4; i++)
kono
parents:
diff changeset
373 {
kono
parents:
diff changeset
374 size = (cif->arg_types)[i]->size;
kono
parents:
diff changeset
375 n = (size + sizeof (int) - 1) / sizeof (int);
kono
parents:
diff changeset
376 if (greg >= NGREGARG)
kono
parents:
diff changeset
377 continue;
kono
parents:
diff changeset
378 else if (greg + n - 1 >= NGREGARG)
kono
parents:
diff changeset
379 n = NGREGARG - greg;
kono
parents:
diff changeset
380 greg += n;
kono
parents:
diff changeset
381 for (m = 0; m < n; m++)
kono
parents:
diff changeset
382 cif->flags += FFI_TYPE_INT << (2 * j++);
kono
parents:
diff changeset
383 }
kono
parents:
diff changeset
384 #endif
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 /* Set the return type flag */
kono
parents:
diff changeset
387 switch (cif->rtype->type)
kono
parents:
diff changeset
388 {
kono
parents:
diff changeset
389 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
390 cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
kono
parents:
diff changeset
391 break;
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 case FFI_TYPE_VOID:
kono
parents:
diff changeset
394 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
395 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
396 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
397 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
398 cif->flags += (unsigned) cif->rtype->type << 24;
kono
parents:
diff changeset
399 break;
kono
parents:
diff changeset
400
kono
parents:
diff changeset
401 default:
kono
parents:
diff changeset
402 cif->flags += FFI_TYPE_INT << 24;
kono
parents:
diff changeset
403 break;
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 return FFI_OK;
kono
parents:
diff changeset
407 }
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
kono
parents:
diff changeset
410 unsigned, unsigned, unsigned *, void (*fn)(void));
kono
parents:
diff changeset
411
kono
parents:
diff changeset
412 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
kono
parents:
diff changeset
413 {
kono
parents:
diff changeset
414 extended_cif ecif;
kono
parents:
diff changeset
415 UINT64 trvalue;
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 ecif.cif = cif;
kono
parents:
diff changeset
418 ecif.avalue = avalue;
kono
parents:
diff changeset
419
kono
parents:
diff changeset
420 /* If the return value is a struct and we don't have a return */
kono
parents:
diff changeset
421 /* value address then we need to make one */
kono
parents:
diff changeset
422
kono
parents:
diff changeset
423 if (cif->rtype->type == FFI_TYPE_STRUCT
kono
parents:
diff changeset
424 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
kono
parents:
diff changeset
425 ecif.rvalue = &trvalue;
kono
parents:
diff changeset
426 else if ((rvalue == NULL) &&
kono
parents:
diff changeset
427 (cif->rtype->type == FFI_TYPE_STRUCT))
kono
parents:
diff changeset
428 {
kono
parents:
diff changeset
429 ecif.rvalue = alloca(cif->rtype->size);
kono
parents:
diff changeset
430 }
kono
parents:
diff changeset
431 else
kono
parents:
diff changeset
432 ecif.rvalue = rvalue;
kono
parents:
diff changeset
433
kono
parents:
diff changeset
434 switch (cif->abi)
kono
parents:
diff changeset
435 {
kono
parents:
diff changeset
436 case FFI_SYSV:
kono
parents:
diff changeset
437 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
kono
parents:
diff changeset
438 fn);
kono
parents:
diff changeset
439 break;
kono
parents:
diff changeset
440 default:
kono
parents:
diff changeset
441 FFI_ASSERT(0);
kono
parents:
diff changeset
442 break;
kono
parents:
diff changeset
443 }
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 if (rvalue
kono
parents:
diff changeset
446 && cif->rtype->type == FFI_TYPE_STRUCT
kono
parents:
diff changeset
447 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
kono
parents:
diff changeset
448 memcpy (rvalue, &trvalue, cif->rtype->size);
kono
parents:
diff changeset
449 }
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 extern void ffi_closure_SYSV (void);
kono
parents:
diff changeset
452 #if defined(__SH4__)
kono
parents:
diff changeset
453 extern void __ic_invalidate (void *line);
kono
parents:
diff changeset
454 #endif
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 ffi_status
kono
parents:
diff changeset
457 ffi_prep_closure_loc (ffi_closure* closure,
kono
parents:
diff changeset
458 ffi_cif* cif,
kono
parents:
diff changeset
459 void (*fun)(ffi_cif*, void*, void**, void*),
kono
parents:
diff changeset
460 void *user_data,
kono
parents:
diff changeset
461 void *codeloc)
kono
parents:
diff changeset
462 {
kono
parents:
diff changeset
463 unsigned int *tramp;
kono
parents:
diff changeset
464 unsigned int insn;
kono
parents:
diff changeset
465
kono
parents:
diff changeset
466 if (cif->abi != FFI_SYSV)
kono
parents:
diff changeset
467 return FFI_BAD_ABI;
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 tramp = (unsigned int *) &closure->tramp[0];
kono
parents:
diff changeset
470 /* Set T bit if the function returns a struct pointed with R2. */
kono
parents:
diff changeset
471 insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT
kono
parents:
diff changeset
472 ? 0x0018 /* sett */
kono
parents:
diff changeset
473 : 0x0008 /* clrt */);
kono
parents:
diff changeset
474
kono
parents:
diff changeset
475 #ifdef __LITTLE_ENDIAN__
kono
parents:
diff changeset
476 tramp[0] = 0xd301d102;
kono
parents:
diff changeset
477 tramp[1] = 0x0000412b | (insn << 16);
kono
parents:
diff changeset
478 #else
kono
parents:
diff changeset
479 tramp[0] = 0xd102d301;
kono
parents:
diff changeset
480 tramp[1] = 0x412b0000 | insn;
kono
parents:
diff changeset
481 #endif
kono
parents:
diff changeset
482 *(void **) &tramp[2] = (void *)codeloc; /* ctx */
kono
parents:
diff changeset
483 *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 closure->cif = cif;
kono
parents:
diff changeset
486 closure->fun = fun;
kono
parents:
diff changeset
487 closure->user_data = user_data;
kono
parents:
diff changeset
488
kono
parents:
diff changeset
489 #if defined(__SH4__)
kono
parents:
diff changeset
490 /* Flush the icache. */
kono
parents:
diff changeset
491 __ic_invalidate(codeloc);
kono
parents:
diff changeset
492 #endif
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 return FFI_OK;
kono
parents:
diff changeset
495 }
kono
parents:
diff changeset
496
kono
parents:
diff changeset
497 /* Basically the trampoline invokes ffi_closure_SYSV, and on
kono
parents:
diff changeset
498 * entry, r3 holds the address of the closure.
kono
parents:
diff changeset
499 * After storing the registers that could possibly contain
kono
parents:
diff changeset
500 * parameters to be passed into the stack frame and setting
kono
parents:
diff changeset
501 * up space for a return value, ffi_closure_SYSV invokes the
kono
parents:
diff changeset
502 * following helper function to do most of the work.
kono
parents:
diff changeset
503 */
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 #ifdef __LITTLE_ENDIAN__
kono
parents:
diff changeset
506 #define OFS_INT8 0
kono
parents:
diff changeset
507 #define OFS_INT16 0
kono
parents:
diff changeset
508 #else
kono
parents:
diff changeset
509 #define OFS_INT8 3
kono
parents:
diff changeset
510 #define OFS_INT16 2
kono
parents:
diff changeset
511 #endif
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 int
kono
parents:
diff changeset
514 ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
kono
parents:
diff changeset
515 unsigned long *pgr, unsigned long *pfr,
kono
parents:
diff changeset
516 unsigned long *pst)
kono
parents:
diff changeset
517 {
kono
parents:
diff changeset
518 void **avalue;
kono
parents:
diff changeset
519 ffi_type **p_arg;
kono
parents:
diff changeset
520 int i, avn;
kono
parents:
diff changeset
521 int ireg, greg = 0;
kono
parents:
diff changeset
522 #if defined(__SH4__)
kono
parents:
diff changeset
523 int freg = 0;
kono
parents:
diff changeset
524 #endif
kono
parents:
diff changeset
525 ffi_cif *cif;
kono
parents:
diff changeset
526
kono
parents:
diff changeset
527 cif = closure->cif;
kono
parents:
diff changeset
528 avalue = alloca(cif->nargs * sizeof(void *));
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 /* Copy the caller's structure return value address so that the closure
kono
parents:
diff changeset
531 returns the data directly to the caller. */
kono
parents:
diff changeset
532 if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
kono
parents:
diff changeset
533 {
kono
parents:
diff changeset
534 rvalue = (void *) *pgr++;
kono
parents:
diff changeset
535 ireg = 1;
kono
parents:
diff changeset
536 }
kono
parents:
diff changeset
537 else
kono
parents:
diff changeset
538 ireg = 0;
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 cif = closure->cif;
kono
parents:
diff changeset
541 greg = ireg;
kono
parents:
diff changeset
542 avn = cif->nargs;
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 /* Grab the addresses of the arguments from the stack frame. */
kono
parents:
diff changeset
545 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
kono
parents:
diff changeset
546 {
kono
parents:
diff changeset
547 size_t z;
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549 z = (*p_arg)->size;
kono
parents:
diff changeset
550 if (z < sizeof(int))
kono
parents:
diff changeset
551 {
kono
parents:
diff changeset
552 if (greg++ >= NGREGARG)
kono
parents:
diff changeset
553 continue;
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 z = sizeof(int);
kono
parents:
diff changeset
556 switch ((*p_arg)->type)
kono
parents:
diff changeset
557 {
kono
parents:
diff changeset
558 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
559 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
560 avalue[i] = (((char *)pgr) + OFS_INT8);
kono
parents:
diff changeset
561 break;
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
564 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
565 avalue[i] = (((char *)pgr) + OFS_INT16);
kono
parents:
diff changeset
566 break;
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
569 avalue[i] = pgr;
kono
parents:
diff changeset
570 break;
kono
parents:
diff changeset
571
kono
parents:
diff changeset
572 default:
kono
parents:
diff changeset
573 FFI_ASSERT(0);
kono
parents:
diff changeset
574 }
kono
parents:
diff changeset
575 pgr++;
kono
parents:
diff changeset
576 }
kono
parents:
diff changeset
577 else if (z == sizeof(int))
kono
parents:
diff changeset
578 {
kono
parents:
diff changeset
579 #if defined(__SH4__)
kono
parents:
diff changeset
580 if ((*p_arg)->type == FFI_TYPE_FLOAT)
kono
parents:
diff changeset
581 {
kono
parents:
diff changeset
582 if (freg++ >= NFREGARG)
kono
parents:
diff changeset
583 continue;
kono
parents:
diff changeset
584 avalue[i] = pfr;
kono
parents:
diff changeset
585 pfr++;
kono
parents:
diff changeset
586 }
kono
parents:
diff changeset
587 else
kono
parents:
diff changeset
588 #endif
kono
parents:
diff changeset
589 {
kono
parents:
diff changeset
590 if (greg++ >= NGREGARG)
kono
parents:
diff changeset
591 continue;
kono
parents:
diff changeset
592 avalue[i] = pgr;
kono
parents:
diff changeset
593 pgr++;
kono
parents:
diff changeset
594 }
kono
parents:
diff changeset
595 }
kono
parents:
diff changeset
596 #if defined(__SH4__)
kono
parents:
diff changeset
597 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
kono
parents:
diff changeset
598 {
kono
parents:
diff changeset
599 if (freg + 1 >= NFREGARG)
kono
parents:
diff changeset
600 continue;
kono
parents:
diff changeset
601 if (freg & 1)
kono
parents:
diff changeset
602 pfr++;
kono
parents:
diff changeset
603 freg = (freg + 1) & ~1;
kono
parents:
diff changeset
604 freg += 2;
kono
parents:
diff changeset
605 avalue[i] = pfr;
kono
parents:
diff changeset
606 pfr += 2;
kono
parents:
diff changeset
607 }
kono
parents:
diff changeset
608 #endif
kono
parents:
diff changeset
609 else
kono
parents:
diff changeset
610 {
kono
parents:
diff changeset
611 int n = (z + sizeof (int) - 1) / sizeof (int);
kono
parents:
diff changeset
612 #if defined(__SH4__)
kono
parents:
diff changeset
613 if (greg + n - 1 >= NGREGARG)
kono
parents:
diff changeset
614 continue;
kono
parents:
diff changeset
615 #else
kono
parents:
diff changeset
616 if (greg >= NGREGARG)
kono
parents:
diff changeset
617 continue;
kono
parents:
diff changeset
618 #endif
kono
parents:
diff changeset
619 greg += n;
kono
parents:
diff changeset
620 avalue[i] = pgr;
kono
parents:
diff changeset
621 pgr += n;
kono
parents:
diff changeset
622 }
kono
parents:
diff changeset
623 }
kono
parents:
diff changeset
624
kono
parents:
diff changeset
625 greg = ireg;
kono
parents:
diff changeset
626 #if defined(__SH4__)
kono
parents:
diff changeset
627 freg = 0;
kono
parents:
diff changeset
628 #endif
kono
parents:
diff changeset
629
kono
parents:
diff changeset
630 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
kono
parents:
diff changeset
631 {
kono
parents:
diff changeset
632 size_t z;
kono
parents:
diff changeset
633
kono
parents:
diff changeset
634 z = (*p_arg)->size;
kono
parents:
diff changeset
635 if (z < sizeof(int))
kono
parents:
diff changeset
636 {
kono
parents:
diff changeset
637 if (greg++ < NGREGARG)
kono
parents:
diff changeset
638 continue;
kono
parents:
diff changeset
639
kono
parents:
diff changeset
640 z = sizeof(int);
kono
parents:
diff changeset
641 switch ((*p_arg)->type)
kono
parents:
diff changeset
642 {
kono
parents:
diff changeset
643 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
644 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
645 avalue[i] = (((char *)pst) + OFS_INT8);
kono
parents:
diff changeset
646 break;
kono
parents:
diff changeset
647
kono
parents:
diff changeset
648 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
649 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
650 avalue[i] = (((char *)pst) + OFS_INT16);
kono
parents:
diff changeset
651 break;
kono
parents:
diff changeset
652
kono
parents:
diff changeset
653 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
654 avalue[i] = pst;
kono
parents:
diff changeset
655 break;
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 default:
kono
parents:
diff changeset
658 FFI_ASSERT(0);
kono
parents:
diff changeset
659 }
kono
parents:
diff changeset
660 pst++;
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662 else if (z == sizeof(int))
kono
parents:
diff changeset
663 {
kono
parents:
diff changeset
664 #if defined(__SH4__)
kono
parents:
diff changeset
665 if ((*p_arg)->type == FFI_TYPE_FLOAT)
kono
parents:
diff changeset
666 {
kono
parents:
diff changeset
667 if (freg++ < NFREGARG)
kono
parents:
diff changeset
668 continue;
kono
parents:
diff changeset
669 }
kono
parents:
diff changeset
670 else
kono
parents:
diff changeset
671 #endif
kono
parents:
diff changeset
672 {
kono
parents:
diff changeset
673 if (greg++ < NGREGARG)
kono
parents:
diff changeset
674 continue;
kono
parents:
diff changeset
675 }
kono
parents:
diff changeset
676 avalue[i] = pst;
kono
parents:
diff changeset
677 pst++;
kono
parents:
diff changeset
678 }
kono
parents:
diff changeset
679 #if defined(__SH4__)
kono
parents:
diff changeset
680 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
kono
parents:
diff changeset
681 {
kono
parents:
diff changeset
682 if (freg + 1 < NFREGARG)
kono
parents:
diff changeset
683 {
kono
parents:
diff changeset
684 freg = (freg + 1) & ~1;
kono
parents:
diff changeset
685 freg += 2;
kono
parents:
diff changeset
686 continue;
kono
parents:
diff changeset
687 }
kono
parents:
diff changeset
688 avalue[i] = pst;
kono
parents:
diff changeset
689 pst += 2;
kono
parents:
diff changeset
690 }
kono
parents:
diff changeset
691 #endif
kono
parents:
diff changeset
692 else
kono
parents:
diff changeset
693 {
kono
parents:
diff changeset
694 int n = (z + sizeof (int) - 1) / sizeof (int);
kono
parents:
diff changeset
695 if (greg + n - 1 < NGREGARG)
kono
parents:
diff changeset
696 {
kono
parents:
diff changeset
697 greg += n;
kono
parents:
diff changeset
698 continue;
kono
parents:
diff changeset
699 }
kono
parents:
diff changeset
700 #if (! defined(__SH4__))
kono
parents:
diff changeset
701 else if (greg < NGREGARG)
kono
parents:
diff changeset
702 {
kono
parents:
diff changeset
703 greg += n;
kono
parents:
diff changeset
704 pst += greg - NGREGARG;
kono
parents:
diff changeset
705 continue;
kono
parents:
diff changeset
706 }
kono
parents:
diff changeset
707 #endif
kono
parents:
diff changeset
708 avalue[i] = pst;
kono
parents:
diff changeset
709 pst += n;
kono
parents:
diff changeset
710 }
kono
parents:
diff changeset
711 }
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 (closure->fun) (cif, rvalue, avalue, closure->user_data);
kono
parents:
diff changeset
714
kono
parents:
diff changeset
715 /* Tell ffi_closure_SYSV how to perform return type promotions. */
kono
parents:
diff changeset
716 return return_type (cif->rtype);
kono
parents:
diff changeset
717 }