1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2002, 2003, 2004, 2005 Kaz Kojima
4 SuperH Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
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 CYGNUS SOLUTIONS 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 ----------------------------------------------------------------------- */
27 #include <ffi_common.h>
36 #if defined(__HITACHI__)
37 #define STRUCT_VALUE_ADDRESS_WITH_ARG 1
39 #define STRUCT_VALUE_ADDRESS_WITH_ARG 0
42 /* If the structure has essentialy an unique element, return its type. */
44 simple_type (ffi_type
*arg
)
46 if (arg
->type
!= FFI_TYPE_STRUCT
)
48 else if (arg
->elements
[1])
49 return FFI_TYPE_STRUCT
;
51 return simple_type (arg
->elements
[0]);
55 return_type (ffi_type
*arg
)
59 if (arg
->type
!= FFI_TYPE_STRUCT
)
62 type
= simple_type (arg
->elements
[0]);
63 if (! arg
->elements
[1])
80 /* gcc uses r0/r1 pair for some kind of structures. */
81 if (arg
->size
<= 2 * sizeof (int))
86 while ((e
= arg
->elements
[i
++]))
88 type
= simple_type (e
);
95 return FFI_TYPE_UINT64
;
103 return FFI_TYPE_STRUCT
;
106 /* ffi_prep_args is called by the assembly routine once stack space
107 has been allocated for the function's arguments */
110 void ffi_prep_args(char *stack
, extended_cif
*ecif
)
113 register unsigned int i
;
115 register unsigned int avn
;
116 register void **p_argv
;
118 register ffi_type
**p_arg
;
127 if (return_type (ecif
->cif
->rtype
) == FFI_TYPE_STRUCT
)
129 *(void **) argp
= ecif
->rvalue
;
131 ireg
= STRUCT_VALUE_ADDRESS_WITH_ARG
? 1 : 0;
136 /* Set arguments for registers. */
138 avn
= ecif
->cif
->nargs
;
139 p_argv
= ecif
->avalue
;
141 for (i
= 0, p_arg
= ecif
->cif
->arg_types
; i
< avn
; i
++, p_arg
++, p_argv
++)
148 if (greg
++ >= NGREGARG
)
152 switch ((*p_arg
)->type
)
155 *(signed int *) argp
= (signed int)*(SINT8
*)(* p_argv
);
159 *(unsigned int *) argp
= (unsigned int)*(UINT8
*)(* p_argv
);
162 case FFI_TYPE_SINT16
:
163 *(signed int *) argp
= (signed int)*(SINT16
*)(* p_argv
);
166 case FFI_TYPE_UINT16
:
167 *(unsigned int *) argp
= (unsigned int)*(UINT16
*)(* p_argv
);
170 case FFI_TYPE_STRUCT
:
171 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
179 else if (z
== sizeof(int))
182 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
184 if (freg
++ >= NFREGARG
)
190 if (greg
++ >= NGREGARG
)
193 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
197 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
199 if (freg
+ 1 >= NFREGARG
)
201 freg
= (freg
+ 1) & ~1;
203 memcpy (argp
, *p_argv
, z
);
209 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
211 if (greg
+ n
- 1 >= NGREGARG
)
214 if (greg
>= NGREGARG
)
218 memcpy (argp
, *p_argv
, z
);
219 argp
+= n
* sizeof (int);
223 /* Set arguments on stack. */
228 p_argv
= ecif
->avalue
;
230 for (i
= 0, p_arg
= ecif
->cif
->arg_types
; i
< avn
; i
++, p_arg
++, p_argv
++)
237 if (greg
++ < NGREGARG
)
241 switch ((*p_arg
)->type
)
244 *(signed int *) argp
= (signed int)*(SINT8
*)(* p_argv
);
248 *(unsigned int *) argp
= (unsigned int)*(UINT8
*)(* p_argv
);
251 case FFI_TYPE_SINT16
:
252 *(signed int *) argp
= (signed int)*(SINT16
*)(* p_argv
);
255 case FFI_TYPE_UINT16
:
256 *(unsigned int *) argp
= (unsigned int)*(UINT16
*)(* p_argv
);
259 case FFI_TYPE_STRUCT
:
260 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
268 else if (z
== sizeof(int))
271 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
273 if (freg
++ < NFREGARG
)
279 if (greg
++ < NGREGARG
)
282 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
286 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
288 if (freg
+ 1 < NFREGARG
)
290 freg
= (freg
+ 1) & ~1;
294 memcpy (argp
, *p_argv
, z
);
300 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
301 if (greg
+ n
- 1 < NGREGARG
)
306 #if (! defined(__SH4__))
307 else if (greg
< NGREGARG
)
313 memcpy (argp
, *p_argv
, z
);
314 argp
+= n
* sizeof (int);
321 /* Perform machine dependent cif processing */
322 ffi_status
ffi_prep_cif_machdep(ffi_cif
*cif
)
334 greg
= ((return_type (cif
->rtype
) == FFI_TYPE_STRUCT
) &&
335 STRUCT_VALUE_ADDRESS_WITH_ARG
) ? 1 : 0;
338 for (i
= j
= 0; i
< cif
->nargs
&& j
< 12; i
++)
340 type
= (cif
->arg_types
)[i
]->type
;
344 if (freg
>= NFREGARG
)
347 cif
->flags
+= ((cif
->arg_types
)[i
]->type
) << (2 * j
);
351 case FFI_TYPE_DOUBLE
:
352 if ((freg
+ 1) >= NFREGARG
)
354 freg
= (freg
+ 1) & ~1;
356 cif
->flags
+= ((cif
->arg_types
)[i
]->type
) << (2 * j
);
361 size
= (cif
->arg_types
)[i
]->size
;
362 n
= (size
+ sizeof (int) - 1) / sizeof (int);
363 if (greg
+ n
- 1 >= NGREGARG
)
366 for (m
= 0; m
< n
; m
++)
367 cif
->flags
+= FFI_TYPE_INT
<< (2 * j
++);
372 for (i
= j
= 0; i
< cif
->nargs
&& j
< 4; i
++)
374 size
= (cif
->arg_types
)[i
]->size
;
375 n
= (size
+ sizeof (int) - 1) / sizeof (int);
376 if (greg
>= NGREGARG
)
378 else if (greg
+ n
- 1 >= NGREGARG
)
381 for (m
= 0; m
< n
; m
++)
382 cif
->flags
+= FFI_TYPE_INT
<< (2 * j
++);
386 /* Set the return type flag */
387 switch (cif
->rtype
->type
)
389 case FFI_TYPE_STRUCT
:
390 cif
->flags
+= (unsigned) (return_type (cif
->rtype
)) << 24;
395 case FFI_TYPE_DOUBLE
:
396 case FFI_TYPE_SINT64
:
397 case FFI_TYPE_UINT64
:
398 cif
->flags
+= (unsigned) cif
->rtype
->type
<< 24;
402 cif
->flags
+= FFI_TYPE_INT
<< 24;
411 extern void ffi_call_SYSV(void (*)(char *, extended_cif
*),
412 /*@out@*/ extended_cif
*,
414 /*@out@*/ unsigned *,
419 void ffi_call(/*@dependent@*/ ffi_cif
*cif
,
421 /*@out@*/ void *rvalue
,
422 /*@dependent@*/ void **avalue
)
428 ecif
.avalue
= avalue
;
430 /* If the return value is a struct and we don't have a return */
431 /* value address then we need to make one */
433 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
434 && return_type (cif
->rtype
) != FFI_TYPE_STRUCT
)
435 ecif
.rvalue
= &trvalue
;
436 else if ((rvalue
== NULL
) &&
437 (cif
->rtype
->type
== FFI_TYPE_STRUCT
))
440 ecif
.rvalue
= alloca(cif
->rtype
->size
);
444 ecif
.rvalue
= rvalue
;
450 ffi_call_SYSV(ffi_prep_args
, &ecif
, cif
->bytes
,
451 cif
->flags
, ecif
.rvalue
, fn
);
460 && cif
->rtype
->type
== FFI_TYPE_STRUCT
461 && return_type (cif
->rtype
) != FFI_TYPE_STRUCT
)
462 memcpy (rvalue
, &trvalue
, cif
->rtype
->size
);
465 extern void ffi_closure_SYSV (void);
467 extern void __ic_invalidate (void *line
);
471 ffi_prep_closure (ffi_closure
* closure
,
473 void (*fun
)(ffi_cif
*, void*, void**, void*),
479 FFI_ASSERT (cif
->abi
== FFI_GCC_SYSV
);
481 tramp
= (unsigned int *) &closure
->tramp
[0];
482 /* Set T bit if the function returns a struct pointed with R2. */
483 insn
= (return_type (cif
->rtype
) == FFI_TYPE_STRUCT
485 : 0x0008 /* clrt */);
487 #ifdef __LITTLE_ENDIAN__
488 tramp
[0] = 0xd301d102;
489 tramp
[1] = 0x0000412b | (insn
<< 16);
491 tramp
[0] = 0xd102d301;
492 tramp
[1] = 0x412b0000 | insn
;
494 *(void **) &tramp
[2] = (void *)closure
; /* ctx */
495 *(void **) &tramp
[3] = (void *)ffi_closure_SYSV
; /* funaddr */
499 closure
->user_data
= user_data
;
502 /* Flush the icache. */
503 __ic_invalidate(&closure
->tramp
[0]);
509 /* Basically the trampoline invokes ffi_closure_SYSV, and on
510 * entry, r3 holds the address of the closure.
511 * After storing the registers that could possibly contain
512 * parameters to be passed into the stack frame and setting
513 * up space for a return value, ffi_closure_SYSV invokes the
514 * following helper function to do most of the work.
517 #ifdef __LITTLE_ENDIAN__
526 ffi_closure_helper_SYSV (ffi_closure
*closure
, void *rvalue
,
527 unsigned long *pgr
, unsigned long *pfr
,
541 avalue
= alloca(cif
->nargs
* sizeof(void *));
543 /* Copy the caller's structure return value address so that the closure
544 returns the data directly to the caller. */
545 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
&& STRUCT_VALUE_ADDRESS_WITH_ARG
)
557 /* Grab the addresses of the arguments from the stack frame. */
558 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
565 if (greg
++ >= NGREGARG
)
569 switch ((*p_arg
)->type
)
573 avalue
[i
] = (((char *)pgr
) + OFS_INT8
);
576 case FFI_TYPE_SINT16
:
577 case FFI_TYPE_UINT16
:
578 avalue
[i
] = (((char *)pgr
) + OFS_INT16
);
581 case FFI_TYPE_STRUCT
:
590 else if (z
== sizeof(int))
593 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
595 if (freg
++ >= NFREGARG
)
603 if (greg
++ >= NGREGARG
)
610 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
612 if (freg
+ 1 >= NFREGARG
)
614 freg
= (freg
+ 1) & ~1;
622 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
624 if (greg
+ n
- 1 >= NGREGARG
)
627 if (greg
>= NGREGARG
)
641 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
648 if (greg
++ < NGREGARG
)
652 switch ((*p_arg
)->type
)
656 avalue
[i
] = (((char *)pst
) + OFS_INT8
);
659 case FFI_TYPE_SINT16
:
660 case FFI_TYPE_UINT16
:
661 avalue
[i
] = (((char *)pst
) + OFS_INT16
);
664 case FFI_TYPE_STRUCT
:
673 else if (z
== sizeof(int))
676 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
678 if (freg
++ < NFREGARG
)
684 if (greg
++ < NGREGARG
)
691 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
693 if (freg
+ 1 < NFREGARG
)
695 freg
= (freg
+ 1) & ~1;
705 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
706 if (greg
+ n
- 1 < NGREGARG
)
711 #if (! defined(__SH4__))
712 else if (greg
< NGREGARG
)
715 pst
+= greg
- NGREGARG
;
724 (closure
->fun
) (cif
, rvalue
, avalue
, closure
->user_data
);
726 /* Tell ffi_closure_SYSV how to perform return type promotions. */
727 return return_type (cif
->rtype
);