1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 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 */
109 void ffi_prep_args(char *stack
, extended_cif
*ecif
)
111 register unsigned int i
;
113 register unsigned int avn
;
114 register void **p_argv
;
116 register ffi_type
**p_arg
;
125 if (return_type (ecif
->cif
->rtype
) == FFI_TYPE_STRUCT
)
127 *(void **) argp
= ecif
->rvalue
;
129 ireg
= STRUCT_VALUE_ADDRESS_WITH_ARG
? 1 : 0;
134 /* Set arguments for registers. */
136 avn
= ecif
->cif
->nargs
;
137 p_argv
= ecif
->avalue
;
139 for (i
= 0, p_arg
= ecif
->cif
->arg_types
; i
< avn
; i
++, p_arg
++, p_argv
++)
146 if (greg
++ >= NGREGARG
)
150 switch ((*p_arg
)->type
)
153 *(signed int *) argp
= (signed int)*(SINT8
*)(* p_argv
);
157 *(unsigned int *) argp
= (unsigned int)*(UINT8
*)(* p_argv
);
160 case FFI_TYPE_SINT16
:
161 *(signed int *) argp
= (signed int)*(SINT16
*)(* p_argv
);
164 case FFI_TYPE_UINT16
:
165 *(unsigned int *) argp
= (unsigned int)*(UINT16
*)(* p_argv
);
168 case FFI_TYPE_STRUCT
:
169 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
177 else if (z
== sizeof(int))
180 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
182 if (freg
++ >= NFREGARG
)
188 if (greg
++ >= NGREGARG
)
191 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
195 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
197 if (freg
+ 1 >= NFREGARG
)
199 freg
= (freg
+ 1) & ~1;
201 memcpy (argp
, *p_argv
, z
);
207 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
209 if (greg
+ n
- 1 >= NGREGARG
)
212 if (greg
>= NGREGARG
)
216 memcpy (argp
, *p_argv
, z
);
217 argp
+= n
* sizeof (int);
221 /* Set arguments on stack. */
226 p_argv
= ecif
->avalue
;
228 for (i
= 0, p_arg
= ecif
->cif
->arg_types
; i
< avn
; i
++, p_arg
++, p_argv
++)
235 if (greg
++ < NGREGARG
)
239 switch ((*p_arg
)->type
)
242 *(signed int *) argp
= (signed int)*(SINT8
*)(* p_argv
);
246 *(unsigned int *) argp
= (unsigned int)*(UINT8
*)(* p_argv
);
249 case FFI_TYPE_SINT16
:
250 *(signed int *) argp
= (signed int)*(SINT16
*)(* p_argv
);
253 case FFI_TYPE_UINT16
:
254 *(unsigned int *) argp
= (unsigned int)*(UINT16
*)(* p_argv
);
257 case FFI_TYPE_STRUCT
:
258 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
266 else if (z
== sizeof(int))
269 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
271 if (freg
++ < NFREGARG
)
277 if (greg
++ < NGREGARG
)
280 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
284 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
286 if (freg
+ 1 < NFREGARG
)
288 freg
= (freg
+ 1) & ~1;
292 memcpy (argp
, *p_argv
, z
);
298 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
299 if (greg
+ n
- 1 < NGREGARG
)
304 #if (! defined(__SH4__))
305 else if (greg
< NGREGARG
)
311 memcpy (argp
, *p_argv
, z
);
312 argp
+= n
* sizeof (int);
319 /* Perform machine dependent cif processing */
320 ffi_status
ffi_prep_cif_machdep(ffi_cif
*cif
)
332 greg
= ((return_type (cif
->rtype
) == FFI_TYPE_STRUCT
) &&
333 STRUCT_VALUE_ADDRESS_WITH_ARG
) ? 1 : 0;
336 for (i
= j
= 0; i
< cif
->nargs
&& j
< 12; i
++)
338 type
= (cif
->arg_types
)[i
]->type
;
342 if (freg
>= NFREGARG
)
345 cif
->flags
+= ((cif
->arg_types
)[i
]->type
) << (2 * j
);
349 case FFI_TYPE_DOUBLE
:
350 if ((freg
+ 1) >= NFREGARG
)
352 freg
= (freg
+ 1) & ~1;
354 cif
->flags
+= ((cif
->arg_types
)[i
]->type
) << (2 * j
);
359 size
= (cif
->arg_types
)[i
]->size
;
360 n
= (size
+ sizeof (int) - 1) / sizeof (int);
361 if (greg
+ n
- 1 >= NGREGARG
)
364 for (m
= 0; m
< n
; m
++)
365 cif
->flags
+= FFI_TYPE_INT
<< (2 * j
++);
370 for (i
= j
= 0; i
< cif
->nargs
&& j
< 4; i
++)
372 size
= (cif
->arg_types
)[i
]->size
;
373 n
= (size
+ sizeof (int) - 1) / sizeof (int);
374 if (greg
>= NGREGARG
)
376 else if (greg
+ n
- 1 >= NGREGARG
)
379 for (m
= 0; m
< n
; m
++)
380 cif
->flags
+= FFI_TYPE_INT
<< (2 * j
++);
384 /* Set the return type flag */
385 switch (cif
->rtype
->type
)
387 case FFI_TYPE_STRUCT
:
388 cif
->flags
+= (unsigned) (return_type (cif
->rtype
)) << 24;
393 case FFI_TYPE_DOUBLE
:
394 case FFI_TYPE_SINT64
:
395 case FFI_TYPE_UINT64
:
396 cif
->flags
+= (unsigned) cif
->rtype
->type
<< 24;
400 cif
->flags
+= FFI_TYPE_INT
<< 24;
407 extern void ffi_call_SYSV(void (*)(char *, extended_cif
*), extended_cif
*,
408 unsigned, unsigned, unsigned *, void (*fn
)());
410 void ffi_call(ffi_cif
*cif
, void (*fn
)(), void *rvalue
, void **avalue
)
416 ecif
.avalue
= avalue
;
418 /* If the return value is a struct and we don't have a return */
419 /* value address then we need to make one */
421 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
422 && return_type (cif
->rtype
) != FFI_TYPE_STRUCT
)
423 ecif
.rvalue
= &trvalue
;
424 else if ((rvalue
== NULL
) &&
425 (cif
->rtype
->type
== FFI_TYPE_STRUCT
))
427 ecif
.rvalue
= alloca(cif
->rtype
->size
);
430 ecif
.rvalue
= rvalue
;
435 ffi_call_SYSV(ffi_prep_args
, &ecif
, cif
->bytes
, cif
->flags
, ecif
.rvalue
,
444 && cif
->rtype
->type
== FFI_TYPE_STRUCT
445 && return_type (cif
->rtype
) != FFI_TYPE_STRUCT
)
446 memcpy (rvalue
, &trvalue
, cif
->rtype
->size
);
449 extern void ffi_closure_SYSV (void);
451 extern void __ic_invalidate (void *line
);
455 ffi_prep_closure_loc (ffi_closure
* closure
,
457 void (*fun
)(ffi_cif
*, void*, void**, void*),
464 FFI_ASSERT (cif
->abi
== FFI_GCC_SYSV
);
466 tramp
= (unsigned int *) &closure
->tramp
[0];
467 /* Set T bit if the function returns a struct pointed with R2. */
468 insn
= (return_type (cif
->rtype
) == FFI_TYPE_STRUCT
470 : 0x0008 /* clrt */);
472 #ifdef __LITTLE_ENDIAN__
473 tramp
[0] = 0xd301d102;
474 tramp
[1] = 0x0000412b | (insn
<< 16);
476 tramp
[0] = 0xd102d301;
477 tramp
[1] = 0x412b0000 | insn
;
479 *(void **) &tramp
[2] = (void *)codeloc
; /* ctx */
480 *(void **) &tramp
[3] = (void *)ffi_closure_SYSV
; /* funaddr */
484 closure
->user_data
= user_data
;
487 /* Flush the icache. */
488 __ic_invalidate(codeloc
);
494 /* Basically the trampoline invokes ffi_closure_SYSV, and on
495 * entry, r3 holds the address of the closure.
496 * After storing the registers that could possibly contain
497 * parameters to be passed into the stack frame and setting
498 * up space for a return value, ffi_closure_SYSV invokes the
499 * following helper function to do most of the work.
502 #ifdef __LITTLE_ENDIAN__
511 ffi_closure_helper_SYSV (ffi_closure
*closure
, void *rvalue
,
512 unsigned long *pgr
, unsigned long *pfr
,
525 avalue
= alloca(cif
->nargs
* sizeof(void *));
527 /* Copy the caller's structure return value address so that the closure
528 returns the data directly to the caller. */
529 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
&& STRUCT_VALUE_ADDRESS_WITH_ARG
)
531 rvalue
= (void *) *pgr
++;
541 /* Grab the addresses of the arguments from the stack frame. */
542 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
549 if (greg
++ >= NGREGARG
)
553 switch ((*p_arg
)->type
)
557 avalue
[i
] = (((char *)pgr
) + OFS_INT8
);
560 case FFI_TYPE_SINT16
:
561 case FFI_TYPE_UINT16
:
562 avalue
[i
] = (((char *)pgr
) + OFS_INT16
);
565 case FFI_TYPE_STRUCT
:
574 else if (z
== sizeof(int))
577 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
579 if (freg
++ >= NFREGARG
)
587 if (greg
++ >= NGREGARG
)
594 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
596 if (freg
+ 1 >= NFREGARG
)
600 freg
= (freg
+ 1) & ~1;
608 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
610 if (greg
+ n
- 1 >= NGREGARG
)
613 if (greg
>= NGREGARG
)
627 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
634 if (greg
++ < NGREGARG
)
638 switch ((*p_arg
)->type
)
642 avalue
[i
] = (((char *)pst
) + OFS_INT8
);
645 case FFI_TYPE_SINT16
:
646 case FFI_TYPE_UINT16
:
647 avalue
[i
] = (((char *)pst
) + OFS_INT16
);
650 case FFI_TYPE_STRUCT
:
659 else if (z
== sizeof(int))
662 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
664 if (freg
++ < NFREGARG
)
670 if (greg
++ < NGREGARG
)
677 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
679 if (freg
+ 1 < NFREGARG
)
681 freg
= (freg
+ 1) & ~1;
691 int n
= (z
+ sizeof (int) - 1) / sizeof (int);
692 if (greg
+ n
- 1 < NGREGARG
)
697 #if (! defined(__SH4__))
698 else if (greg
< NGREGARG
)
701 pst
+= greg
- NGREGARG
;
710 (closure
->fun
) (cif
, rvalue
, avalue
, closure
->user_data
);
712 /* Tell ffi_closure_SYSV how to perform return type promotions. */
713 return return_type (cif
->rtype
);