]>
Commit | Line | Data |
---|---|---|
22bcf65c | 1 | /* ----------------------------------------------------------------------- |
18fa3240 | 2 | ffi.c - Copyright (c) 2000, 2007 Software AG |
22bcf65c GT |
3 | |
4 | S390 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 THE AUTHOR 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 | /* Includes */ | |
27 | /* -------- */ | |
28 | /*====================================================================*/ | |
29 | ||
30 | #include <ffi.h> | |
31 | #include <ffi_common.h> | |
32 | ||
33 | #include <stdlib.h> | |
34 | #include <stdio.h> | |
35 | ||
36 | /*====================== End of Includes =============================*/ | |
37 | ||
38 | /*====================================================================*/ | |
39 | /* Defines */ | |
40 | /* ------- */ | |
41 | /*====================================================================*/ | |
c4f17c6f UW |
42 | |
43 | /* Maximum number of GPRs available for argument passing. */ | |
44 | #define MAX_GPRARGS 5 | |
45 | ||
46 | /* Maximum number of FPRs available for argument passing. */ | |
47 | #ifdef __s390x__ | |
48 | #define MAX_FPRARGS 4 | |
49 | #else | |
50 | #define MAX_FPRARGS 2 | |
51 | #endif | |
52 | ||
53 | /* Round to multiple of 16. */ | |
54 | #define ROUND_SIZE(size) (((size) + 15) & ~15) | |
55 | ||
56 | /* If these values change, sysv.S must be adapted! */ | |
57 | #define FFI390_RET_VOID 0 | |
58 | #define FFI390_RET_STRUCT 1 | |
59 | #define FFI390_RET_FLOAT 2 | |
60 | #define FFI390_RET_DOUBLE 3 | |
61 | #define FFI390_RET_INT32 4 | |
62 | #define FFI390_RET_INT64 5 | |
63 | ||
22bcf65c GT |
64 | /*===================== End of Defines ===============================*/ |
65 | ||
22bcf65c GT |
66 | /*====================================================================*/ |
67 | /* Prototypes */ | |
68 | /* ---------- */ | |
69 | /*====================================================================*/ | |
70 | ||
c4f17c6f | 71 | static void ffi_prep_args (unsigned char *, extended_cif *); |
0fcc9e55 JJ |
72 | void |
73 | #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) | |
74 | __attribute__ ((visibility ("hidden"))) | |
75 | #endif | |
76 | ffi_closure_helper_SYSV (ffi_closure *, unsigned long *, | |
77 | unsigned long long *, unsigned long *); | |
78 | ||
22bcf65c GT |
79 | /*====================== End of Prototypes ===========================*/ |
80 | ||
81 | /*====================================================================*/ | |
82 | /* Externals */ | |
83 | /* --------- */ | |
84 | /*====================================================================*/ | |
85 | ||
c4f17c6f | 86 | extern void ffi_call_SYSV(unsigned, |
22bcf65c | 87 | extended_cif *, |
c4f17c6f UW |
88 | void (*)(unsigned char *, extended_cif *), |
89 | unsigned, | |
90 | void *, | |
22bcf65c | 91 | void (*fn)()); |
c4f17c6f UW |
92 | |
93 | extern void ffi_closure_SYSV(void); | |
22bcf65c GT |
94 | |
95 | /*====================== End of Externals ============================*/ | |
96 | ||
97 | /*====================================================================*/ | |
98 | /* */ | |
c4f17c6f | 99 | /* Name - ffi_check_struct_type. */ |
22bcf65c GT |
100 | /* */ |
101 | /* Function - Determine if a structure can be passed within a */ | |
c4f17c6f | 102 | /* general purpose or floating point register. */ |
22bcf65c GT |
103 | /* */ |
104 | /*====================================================================*/ | |
105 | ||
c4f17c6f UW |
106 | static int |
107 | ffi_check_struct_type (ffi_type *arg) | |
22bcf65c | 108 | { |
c4f17c6f UW |
109 | size_t size = arg->size; |
110 | ||
111 | /* If the struct has just one element, look at that element | |
112 | to find out whether to consider the struct as floating point. */ | |
113 | while (arg->type == FFI_TYPE_STRUCT | |
114 | && arg->elements[0] && !arg->elements[1]) | |
115 | arg = arg->elements[0]; | |
116 | ||
117 | /* Structs of size 1, 2, 4, and 8 are passed in registers, | |
118 | just like the corresponding int/float types. */ | |
119 | switch (size) | |
120 | { | |
121 | case 1: | |
122 | return FFI_TYPE_UINT8; | |
123 | ||
124 | case 2: | |
125 | return FFI_TYPE_UINT16; | |
126 | ||
127 | case 4: | |
128 | if (arg->type == FFI_TYPE_FLOAT) | |
129 | return FFI_TYPE_FLOAT; | |
130 | else | |
131 | return FFI_TYPE_UINT32; | |
132 | ||
133 | case 8: | |
134 | if (arg->type == FFI_TYPE_DOUBLE) | |
135 | return FFI_TYPE_DOUBLE; | |
136 | else | |
137 | return FFI_TYPE_UINT64; | |
138 | ||
139 | default: | |
140 | break; | |
141 | } | |
142 | ||
143 | /* Other structs are passed via a pointer to the data. */ | |
144 | return FFI_TYPE_POINTER; | |
22bcf65c GT |
145 | } |
146 | ||
147 | /*======================== End of Routine ============================*/ | |
148 | ||
149 | /*====================================================================*/ | |
150 | /* */ | |
c4f17c6f UW |
151 | /* Name - ffi_prep_args. */ |
152 | /* */ | |
153 | /* Function - Prepare parameters for call to function. */ | |
22bcf65c | 154 | /* */ |
c4f17c6f UW |
155 | /* ffi_prep_args is called by the assembly routine once stack space */ |
156 | /* has been allocated for the function's arguments. */ | |
22bcf65c GT |
157 | /* */ |
158 | /*====================================================================*/ | |
159 | ||
c4f17c6f UW |
160 | static void |
161 | ffi_prep_args (unsigned char *stack, extended_cif *ecif) | |
22bcf65c | 162 | { |
c4f17c6f UW |
163 | /* The stack space will be filled with those areas: |
164 | ||
165 | FPR argument register save area (highest addresses) | |
166 | GPR argument register save area | |
167 | temporary struct copies | |
168 | overflow argument area (lowest addresses) | |
169 | ||
170 | We set up the following pointers: | |
171 | ||
172 | p_fpr: bottom of the FPR area (growing upwards) | |
173 | p_gpr: bottom of the GPR area (growing upwards) | |
174 | p_ov: bottom of the overflow area (growing upwards) | |
175 | p_struct: top of the struct copy area (growing downwards) | |
176 | ||
177 | All areas are kept aligned to twice the word size. */ | |
178 | ||
179 | int gpr_off = ecif->cif->bytes; | |
180 | int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long)); | |
181 | ||
182 | unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off); | |
183 | unsigned long *p_gpr = (unsigned long *)(stack + gpr_off); | |
184 | unsigned char *p_struct = (unsigned char *)p_gpr; | |
185 | unsigned long *p_ov = (unsigned long *)stack; | |
186 | ||
187 | int n_fpr = 0; | |
188 | int n_gpr = 0; | |
189 | int n_ov = 0; | |
190 | ||
191 | ffi_type **ptr; | |
192 | void **p_argv = ecif->avalue; | |
193 | int i; | |
194 | ||
195 | /* If we returning a structure then we set the first parameter register | |
196 | to the address of where we are returning this structure. */ | |
197 | ||
198 | if (ecif->cif->flags == FFI390_RET_STRUCT) | |
199 | p_gpr[n_gpr++] = (unsigned long) ecif->rvalue; | |
200 | ||
201 | /* Now for the arguments. */ | |
22bcf65c | 202 | |
c4f17c6f UW |
203 | for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; |
204 | i > 0; | |
205 | i--, ptr++, p_argv++) | |
206 | { | |
207 | void *arg = *p_argv; | |
208 | int type = (*ptr)->type; | |
209 | ||
7a23933b AK |
210 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
211 | /* 16-byte long double is passed like a struct. */ | |
212 | if (type == FFI_TYPE_LONGDOUBLE) | |
213 | type = FFI_TYPE_STRUCT; | |
214 | #endif | |
215 | ||
c4f17c6f UW |
216 | /* Check how a structure type is passed. */ |
217 | if (type == FFI_TYPE_STRUCT) | |
218 | { | |
219 | type = ffi_check_struct_type (*ptr); | |
220 | ||
221 | /* If we pass the struct via pointer, copy the data. */ | |
222 | if (type == FFI_TYPE_POINTER) | |
223 | { | |
224 | p_struct -= ROUND_SIZE ((*ptr)->size); | |
225 | memcpy (p_struct, (char *)arg, (*ptr)->size); | |
226 | arg = &p_struct; | |
227 | } | |
228 | } | |
229 | ||
e5dce82f | 230 | /* Now handle all primitive int/pointer/float data types. */ |
c4f17c6f UW |
231 | switch (type) |
232 | { | |
233 | case FFI_TYPE_DOUBLE: | |
234 | if (n_fpr < MAX_FPRARGS) | |
235 | p_fpr[n_fpr++] = *(unsigned long long *) arg; | |
236 | else | |
237 | #ifdef __s390x__ | |
238 | p_ov[n_ov++] = *(unsigned long *) arg; | |
239 | #else | |
240 | p_ov[n_ov++] = ((unsigned long *) arg)[0], | |
241 | p_ov[n_ov++] = ((unsigned long *) arg)[1]; | |
242 | #endif | |
243 | break; | |
244 | ||
245 | case FFI_TYPE_FLOAT: | |
246 | if (n_fpr < MAX_FPRARGS) | |
247 | p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32; | |
248 | else | |
249 | p_ov[n_ov++] = *(unsigned int *) arg; | |
250 | break; | |
e5dce82f UW |
251 | |
252 | case FFI_TYPE_POINTER: | |
253 | if (n_gpr < MAX_GPRARGS) | |
254 | p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg; | |
255 | else | |
256 | p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg; | |
257 | break; | |
c4f17c6f UW |
258 | |
259 | case FFI_TYPE_UINT64: | |
260 | case FFI_TYPE_SINT64: | |
261 | #ifdef __s390x__ | |
262 | if (n_gpr < MAX_GPRARGS) | |
263 | p_gpr[n_gpr++] = *(unsigned long *) arg; | |
264 | else | |
265 | p_ov[n_ov++] = *(unsigned long *) arg; | |
266 | #else | |
267 | if (n_gpr == MAX_GPRARGS-1) | |
268 | n_gpr = MAX_GPRARGS; | |
269 | if (n_gpr < MAX_GPRARGS) | |
270 | p_gpr[n_gpr++] = ((unsigned long *) arg)[0], | |
271 | p_gpr[n_gpr++] = ((unsigned long *) arg)[1]; | |
272 | else | |
273 | p_ov[n_ov++] = ((unsigned long *) arg)[0], | |
274 | p_ov[n_ov++] = ((unsigned long *) arg)[1]; | |
275 | #endif | |
276 | break; | |
277 | ||
278 | case FFI_TYPE_UINT32: | |
279 | if (n_gpr < MAX_GPRARGS) | |
280 | p_gpr[n_gpr++] = *(unsigned int *) arg; | |
281 | else | |
282 | p_ov[n_ov++] = *(unsigned int *) arg; | |
283 | break; | |
284 | ||
285 | case FFI_TYPE_INT: | |
286 | case FFI_TYPE_SINT32: | |
287 | if (n_gpr < MAX_GPRARGS) | |
288 | p_gpr[n_gpr++] = *(signed int *) arg; | |
289 | else | |
290 | p_ov[n_ov++] = *(signed int *) arg; | |
291 | break; | |
292 | ||
293 | case FFI_TYPE_UINT16: | |
294 | if (n_gpr < MAX_GPRARGS) | |
295 | p_gpr[n_gpr++] = *(unsigned short *) arg; | |
296 | else | |
297 | p_ov[n_ov++] = *(unsigned short *) arg; | |
298 | break; | |
299 | ||
300 | case FFI_TYPE_SINT16: | |
301 | if (n_gpr < MAX_GPRARGS) | |
302 | p_gpr[n_gpr++] = *(signed short *) arg; | |
303 | else | |
304 | p_ov[n_ov++] = *(signed short *) arg; | |
305 | break; | |
306 | ||
307 | case FFI_TYPE_UINT8: | |
308 | if (n_gpr < MAX_GPRARGS) | |
309 | p_gpr[n_gpr++] = *(unsigned char *) arg; | |
310 | else | |
311 | p_ov[n_ov++] = *(unsigned char *) arg; | |
312 | break; | |
313 | ||
314 | case FFI_TYPE_SINT8: | |
315 | if (n_gpr < MAX_GPRARGS) | |
316 | p_gpr[n_gpr++] = *(signed char *) arg; | |
317 | else | |
318 | p_ov[n_ov++] = *(signed char *) arg; | |
319 | break; | |
320 | ||
321 | default: | |
322 | FFI_ASSERT (0); | |
323 | break; | |
324 | } | |
325 | } | |
326 | } | |
327 | ||
22bcf65c GT |
328 | /*======================== End of Routine ============================*/ |
329 | ||
330 | /*====================================================================*/ | |
331 | /* */ | |
c4f17c6f | 332 | /* Name - ffi_prep_cif_machdep. */ |
22bcf65c | 333 | /* */ |
c4f17c6f | 334 | /* Function - Perform machine dependent CIF processing. */ |
22bcf65c GT |
335 | /* */ |
336 | /*====================================================================*/ | |
337 | ||
c4f17c6f UW |
338 | ffi_status |
339 | ffi_prep_cif_machdep(ffi_cif *cif) | |
22bcf65c | 340 | { |
c4f17c6f UW |
341 | size_t struct_size = 0; |
342 | int n_gpr = 0; | |
343 | int n_fpr = 0; | |
344 | int n_ov = 0; | |
345 | ||
346 | ffi_type **ptr; | |
347 | int i; | |
348 | ||
349 | /* Determine return value handling. */ | |
350 | ||
351 | switch (cif->rtype->type) | |
352 | { | |
353 | /* Void is easy. */ | |
354 | case FFI_TYPE_VOID: | |
355 | cif->flags = FFI390_RET_VOID; | |
356 | break; | |
357 | ||
358 | /* Structures are returned via a hidden pointer. */ | |
359 | case FFI_TYPE_STRUCT: | |
360 | cif->flags = FFI390_RET_STRUCT; | |
361 | n_gpr++; /* We need one GPR to pass the pointer. */ | |
362 | break; | |
363 | ||
364 | /* Floating point values are returned in fpr 0. */ | |
365 | case FFI_TYPE_FLOAT: | |
366 | cif->flags = FFI390_RET_FLOAT; | |
367 | break; | |
368 | ||
369 | case FFI_TYPE_DOUBLE: | |
370 | cif->flags = FFI390_RET_DOUBLE; | |
371 | break; | |
372 | ||
7a23933b AK |
373 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
374 | case FFI_TYPE_LONGDOUBLE: | |
375 | cif->flags = FFI390_RET_STRUCT; | |
376 | n_gpr++; | |
377 | break; | |
378 | #endif | |
c4f17c6f UW |
379 | /* Integer values are returned in gpr 2 (and gpr 3 |
380 | for 64-bit values on 31-bit machines). */ | |
381 | case FFI_TYPE_UINT64: | |
382 | case FFI_TYPE_SINT64: | |
383 | cif->flags = FFI390_RET_INT64; | |
384 | break; | |
385 | ||
8177895b | 386 | case FFI_TYPE_POINTER: |
c4f17c6f UW |
387 | case FFI_TYPE_INT: |
388 | case FFI_TYPE_UINT32: | |
389 | case FFI_TYPE_SINT32: | |
390 | case FFI_TYPE_UINT16: | |
391 | case FFI_TYPE_SINT16: | |
392 | case FFI_TYPE_UINT8: | |
393 | case FFI_TYPE_SINT8: | |
394 | /* These are to be extended to word size. */ | |
395 | #ifdef __s390x__ | |
396 | cif->flags = FFI390_RET_INT64; | |
397 | #else | |
398 | cif->flags = FFI390_RET_INT32; | |
399 | #endif | |
400 | break; | |
22bcf65c | 401 | |
c4f17c6f UW |
402 | default: |
403 | FFI_ASSERT (0); | |
404 | break; | |
405 | } | |
406 | ||
407 | /* Now for the arguments. */ | |
22bcf65c | 408 | |
c4f17c6f UW |
409 | for (ptr = cif->arg_types, i = cif->nargs; |
410 | i > 0; | |
411 | i--, ptr++) | |
412 | { | |
413 | int type = (*ptr)->type; | |
414 | ||
7a23933b AK |
415 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
416 | /* 16-byte long double is passed like a struct. */ | |
417 | if (type == FFI_TYPE_LONGDOUBLE) | |
418 | type = FFI_TYPE_STRUCT; | |
419 | #endif | |
420 | ||
c4f17c6f UW |
421 | /* Check how a structure type is passed. */ |
422 | if (type == FFI_TYPE_STRUCT) | |
423 | { | |
424 | type = ffi_check_struct_type (*ptr); | |
425 | ||
426 | /* If we pass the struct via pointer, we must reserve space | |
427 | to copy its data for proper call-by-value semantics. */ | |
428 | if (type == FFI_TYPE_POINTER) | |
429 | struct_size += ROUND_SIZE ((*ptr)->size); | |
430 | } | |
431 | ||
432 | /* Now handle all primitive int/float data types. */ | |
433 | switch (type) | |
434 | { | |
435 | /* The first MAX_FPRARGS floating point arguments | |
436 | go in FPRs, the rest overflow to the stack. */ | |
437 | ||
438 | case FFI_TYPE_DOUBLE: | |
439 | if (n_fpr < MAX_FPRARGS) | |
440 | n_fpr++; | |
441 | else | |
442 | n_ov += sizeof (double) / sizeof (long); | |
443 | break; | |
444 | ||
445 | case FFI_TYPE_FLOAT: | |
446 | if (n_fpr < MAX_FPRARGS) | |
447 | n_fpr++; | |
448 | else | |
449 | n_ov++; | |
450 | break; | |
451 | ||
452 | /* On 31-bit machines, 64-bit integers are passed in GPR pairs, | |
453 | if one is still available, or else on the stack. If only one | |
454 | register is free, skip the register (it won't be used for any | |
455 | subsequent argument either). */ | |
456 | ||
457 | #ifndef __s390x__ | |
458 | case FFI_TYPE_UINT64: | |
459 | case FFI_TYPE_SINT64: | |
460 | if (n_gpr == MAX_GPRARGS-1) | |
461 | n_gpr = MAX_GPRARGS; | |
462 | if (n_gpr < MAX_GPRARGS) | |
463 | n_gpr += 2; | |
464 | else | |
465 | n_ov += 2; | |
466 | break; | |
467 | #endif | |
468 | ||
469 | /* Everything else is passed in GPRs (until MAX_GPRARGS | |
470 | have been used) or overflows to the stack. */ | |
471 | ||
472 | default: | |
473 | if (n_gpr < MAX_GPRARGS) | |
474 | n_gpr++; | |
475 | else | |
476 | n_ov++; | |
477 | break; | |
478 | } | |
479 | } | |
480 | ||
481 | /* Total stack space as required for overflow arguments | |
482 | and temporary structure copies. */ | |
483 | ||
484 | cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size; | |
485 | ||
486 | return FFI_OK; | |
22bcf65c GT |
487 | } |
488 | ||
489 | /*======================== End of Routine ============================*/ | |
490 | ||
491 | /*====================================================================*/ | |
492 | /* */ | |
c4f17c6f | 493 | /* Name - ffi_call. */ |
22bcf65c | 494 | /* */ |
c4f17c6f | 495 | /* Function - Call the FFI routine. */ |
22bcf65c GT |
496 | /* */ |
497 | /*====================================================================*/ | |
498 | ||
499 | void | |
c4f17c6f UW |
500 | ffi_call(ffi_cif *cif, |
501 | void (*fn)(), | |
502 | void *rvalue, | |
503 | void **avalue) | |
22bcf65c | 504 | { |
c4f17c6f UW |
505 | int ret_type = cif->flags; |
506 | extended_cif ecif; | |
22bcf65c | 507 | |
c4f17c6f UW |
508 | ecif.cif = cif; |
509 | ecif.avalue = avalue; | |
510 | ecif.rvalue = rvalue; | |
511 | ||
512 | /* If we don't have a return value, we need to fake one. */ | |
513 | if (rvalue == NULL) | |
514 | { | |
515 | if (ret_type == FFI390_RET_STRUCT) | |
516 | ecif.rvalue = alloca (cif->rtype->size); | |
517 | else | |
518 | ret_type = FFI390_RET_VOID; | |
519 | } | |
520 | ||
521 | switch (cif->abi) | |
522 | { | |
523 | case FFI_SYSV: | |
524 | ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args, | |
525 | ret_type, ecif.rvalue, fn); | |
526 | break; | |
527 | ||
528 | default: | |
529 | FFI_ASSERT (0); | |
530 | break; | |
531 | } | |
22bcf65c GT |
532 | } |
533 | ||
534 | /*======================== End of Routine ============================*/ | |
c4f17c6f | 535 | |
22bcf65c GT |
536 | /*====================================================================*/ |
537 | /* */ | |
c4f17c6f | 538 | /* Name - ffi_closure_helper_SYSV. */ |
22bcf65c | 539 | /* */ |
c4f17c6f | 540 | /* Function - Call a FFI closure target function. */ |
22bcf65c GT |
541 | /* */ |
542 | /*====================================================================*/ | |
543 | ||
544 | void | |
c4f17c6f UW |
545 | ffi_closure_helper_SYSV (ffi_closure *closure, |
546 | unsigned long *p_gpr, | |
547 | unsigned long long *p_fpr, | |
548 | unsigned long *p_ov) | |
22bcf65c | 549 | { |
c4f17c6f UW |
550 | unsigned long long ret_buffer; |
551 | ||
552 | void *rvalue = &ret_buffer; | |
553 | void **avalue; | |
554 | void **p_arg; | |
555 | ||
556 | int n_gpr = 0; | |
557 | int n_fpr = 0; | |
558 | int n_ov = 0; | |
559 | ||
22bcf65c | 560 | ffi_type **ptr; |
c4f17c6f UW |
561 | int i; |
562 | ||
563 | /* Allocate buffer for argument list pointers. */ | |
564 | ||
565 | p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *)); | |
566 | ||
567 | /* If we returning a structure, pass the structure address | |
568 | directly to the target function. Otherwise, have the target | |
569 | function store the return value to the GPR save area. */ | |
570 | ||
571 | if (closure->cif->flags == FFI390_RET_STRUCT) | |
572 | rvalue = (void *) p_gpr[n_gpr++]; | |
573 | ||
22bcf65c | 574 | /* Now for the arguments. */ |
c4f17c6f UW |
575 | |
576 | for (ptr = closure->cif->arg_types, i = closure->cif->nargs; | |
22bcf65c | 577 | i > 0; |
c4f17c6f | 578 | i--, p_arg++, ptr++) |
22bcf65c | 579 | { |
c4f17c6f UW |
580 | int deref_struct_pointer = 0; |
581 | int type = (*ptr)->type; | |
582 | ||
7a23933b AK |
583 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
584 | /* 16-byte long double is passed like a struct. */ | |
585 | if (type == FFI_TYPE_LONGDOUBLE) | |
586 | type = FFI_TYPE_STRUCT; | |
587 | #endif | |
588 | ||
c4f17c6f UW |
589 | /* Check how a structure type is passed. */ |
590 | if (type == FFI_TYPE_STRUCT) | |
591 | { | |
592 | type = ffi_check_struct_type (*ptr); | |
593 | ||
594 | /* If we pass the struct via pointer, remember to | |
595 | retrieve the pointer later. */ | |
596 | if (type == FFI_TYPE_POINTER) | |
597 | deref_struct_pointer = 1; | |
598 | } | |
599 | ||
600 | /* Pointers are passed like UINTs of the same size. */ | |
601 | if (type == FFI_TYPE_POINTER) | |
602 | #ifdef __s390x__ | |
603 | type = FFI_TYPE_UINT64; | |
604 | #else | |
605 | type = FFI_TYPE_UINT32; | |
606 | #endif | |
607 | ||
608 | /* Now handle all primitive int/float data types. */ | |
609 | switch (type) | |
610 | { | |
611 | case FFI_TYPE_DOUBLE: | |
612 | if (n_fpr < MAX_FPRARGS) | |
613 | *p_arg = &p_fpr[n_fpr++]; | |
614 | else | |
615 | *p_arg = &p_ov[n_ov], | |
616 | n_ov += sizeof (double) / sizeof (long); | |
617 | break; | |
618 | ||
619 | case FFI_TYPE_FLOAT: | |
620 | if (n_fpr < MAX_FPRARGS) | |
621 | *p_arg = &p_fpr[n_fpr++]; | |
622 | else | |
623 | *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; | |
624 | break; | |
625 | ||
626 | case FFI_TYPE_UINT64: | |
627 | case FFI_TYPE_SINT64: | |
628 | #ifdef __s390x__ | |
629 | if (n_gpr < MAX_GPRARGS) | |
630 | *p_arg = &p_gpr[n_gpr++]; | |
631 | else | |
632 | *p_arg = &p_ov[n_ov++]; | |
633 | #else | |
634 | if (n_gpr == MAX_GPRARGS-1) | |
635 | n_gpr = MAX_GPRARGS; | |
636 | if (n_gpr < MAX_GPRARGS) | |
637 | *p_arg = &p_gpr[n_gpr], n_gpr += 2; | |
638 | else | |
639 | *p_arg = &p_ov[n_ov], n_ov += 2; | |
640 | #endif | |
641 | break; | |
642 | ||
643 | case FFI_TYPE_INT: | |
644 | case FFI_TYPE_UINT32: | |
645 | case FFI_TYPE_SINT32: | |
646 | if (n_gpr < MAX_GPRARGS) | |
647 | *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4; | |
648 | else | |
649 | *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; | |
650 | break; | |
651 | ||
652 | case FFI_TYPE_UINT16: | |
653 | case FFI_TYPE_SINT16: | |
654 | if (n_gpr < MAX_GPRARGS) | |
655 | *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2; | |
656 | else | |
657 | *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2; | |
658 | break; | |
659 | ||
660 | case FFI_TYPE_UINT8: | |
661 | case FFI_TYPE_SINT8: | |
662 | if (n_gpr < MAX_GPRARGS) | |
663 | *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1; | |
664 | else | |
665 | *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1; | |
666 | break; | |
667 | ||
668 | default: | |
669 | FFI_ASSERT (0); | |
670 | break; | |
671 | } | |
672 | ||
673 | /* If this is a struct passed via pointer, we need to | |
674 | actually retrieve that pointer. */ | |
675 | if (deref_struct_pointer) | |
676 | *p_arg = *(void **)*p_arg; | |
677 | } | |
678 | ||
679 | ||
680 | /* Call the target function. */ | |
681 | (closure->fun) (closure->cif, rvalue, avalue, closure->user_data); | |
682 | ||
683 | /* Convert the return value. */ | |
684 | switch (closure->cif->rtype->type) | |
685 | { | |
686 | /* Void is easy, and so is struct. */ | |
687 | case FFI_TYPE_VOID: | |
688 | case FFI_TYPE_STRUCT: | |
7a23933b AK |
689 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
690 | case FFI_TYPE_LONGDOUBLE: | |
691 | #endif | |
c4f17c6f UW |
692 | break; |
693 | ||
694 | /* Floating point values are returned in fpr 0. */ | |
22bcf65c | 695 | case FFI_TYPE_FLOAT: |
c4f17c6f | 696 | p_fpr[0] = (long long) *(unsigned int *) rvalue << 32; |
22bcf65c | 697 | break; |
c4f17c6f | 698 | |
22bcf65c | 699 | case FFI_TYPE_DOUBLE: |
c4f17c6f | 700 | p_fpr[0] = *(unsigned long long *) rvalue; |
22bcf65c | 701 | break; |
c4f17c6f UW |
702 | |
703 | /* Integer values are returned in gpr 2 (and gpr 3 | |
704 | for 64-bit values on 31-bit machines). */ | |
22bcf65c GT |
705 | case FFI_TYPE_UINT64: |
706 | case FFI_TYPE_SINT64: | |
c4f17c6f UW |
707 | #ifdef __s390x__ |
708 | p_gpr[0] = *(unsigned long *) rvalue; | |
709 | #else | |
710 | p_gpr[0] = ((unsigned long *) rvalue)[0], | |
711 | p_gpr[1] = ((unsigned long *) rvalue)[1]; | |
712 | #endif | |
22bcf65c | 713 | break; |
c4f17c6f | 714 | |
8177895b | 715 | case FFI_TYPE_POINTER: |
c4f17c6f | 716 | case FFI_TYPE_UINT32: |
8177895b UW |
717 | case FFI_TYPE_UINT16: |
718 | case FFI_TYPE_UINT8: | |
719 | p_gpr[0] = *(unsigned long *) rvalue; | |
22bcf65c | 720 | break; |
c4f17c6f UW |
721 | |
722 | case FFI_TYPE_INT: | |
723 | case FFI_TYPE_SINT32: | |
22bcf65c | 724 | case FFI_TYPE_SINT16: |
c4f17c6f | 725 | case FFI_TYPE_SINT8: |
8177895b | 726 | p_gpr[0] = *(signed long *) rvalue; |
22bcf65c | 727 | break; |
c4f17c6f UW |
728 | |
729 | default: | |
730 | FFI_ASSERT (0); | |
731 | break; | |
22bcf65c GT |
732 | } |
733 | } | |
22bcf65c | 734 | |
c4f17c6f UW |
735 | /*======================== End of Routine ============================*/ |
736 | ||
22bcf65c GT |
737 | /*====================================================================*/ |
738 | /* */ | |
18fa3240 | 739 | /* Name - ffi_prep_closure_loc. */ |
22bcf65c | 740 | /* */ |
c4f17c6f | 741 | /* Function - Prepare a FFI closure. */ |
22bcf65c GT |
742 | /* */ |
743 | /*====================================================================*/ | |
744 | ||
745 | ffi_status | |
18fa3240 AO |
746 | ffi_prep_closure_loc (ffi_closure *closure, |
747 | ffi_cif *cif, | |
748 | void (*fun) (ffi_cif *, void *, void **, void *), | |
749 | void *user_data, | |
750 | void *codeloc) | |
22bcf65c | 751 | { |
c4f17c6f UW |
752 | FFI_ASSERT (cif->abi == FFI_SYSV); |
753 | ||
754 | #ifndef __s390x__ | |
755 | *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ | |
756 | *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */ | |
757 | *(short *)&closure->tramp [4] = 0x1006; | |
758 | *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */ | |
18fa3240 | 759 | *(long *)&closure->tramp [8] = (long)codeloc; |
c4f17c6f UW |
760 | *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV; |
761 | #else | |
762 | *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ | |
763 | *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */ | |
764 | *(short *)&closure->tramp [4] = 0x100e; | |
765 | *(short *)&closure->tramp [6] = 0x0004; | |
766 | *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */ | |
18fa3240 | 767 | *(long *)&closure->tramp[16] = (long)codeloc; |
c4f17c6f UW |
768 | *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV; |
769 | #endif | |
770 | ||
771 | closure->cif = cif; | |
772 | closure->user_data = user_data; | |
773 | closure->fun = fun; | |
22bcf65c GT |
774 | |
775 | return FFI_OK; | |
776 | } | |
c4f17c6f | 777 | |
22bcf65c GT |
778 | /*======================== End of Routine ============================*/ |
779 |