Ruby: ext/fiddle/libffi-3.2.1/src/sh/ffi.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

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