1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998 Cygnus Solutions
3 Copyright (c) 2004 Simon Posnjak
4 Copyright (c) 2005 Axis Communications AB
5 Copyright (C) 2007 Free Software Foundation, Inc.
7 CRIS Foreign Function Interface
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 ``Software''), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27 ----------------------------------------------------------------------- */
30 #include <ffi_common.h>
32 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
35 initialize_aggregate_packed_struct (ffi_type
* arg
)
39 FFI_ASSERT (arg
!= NULL
);
41 FFI_ASSERT (arg
->elements
!= NULL
);
42 FFI_ASSERT (arg
->size
== 0);
43 FFI_ASSERT (arg
->alignment
== 0);
45 ptr
= &(arg
->elements
[0]);
47 while ((*ptr
) != NULL
)
49 if (((*ptr
)->size
== 0)
50 && (initialize_aggregate_packed_struct ((*ptr
)) != FFI_OK
))
51 return FFI_BAD_TYPEDEF
;
53 FFI_ASSERT (ffi_type_test ((*ptr
)));
55 arg
->size
+= (*ptr
)->size
;
57 arg
->alignment
= (arg
->alignment
> (*ptr
)->alignment
) ?
58 arg
->alignment
: (*ptr
)->alignment
;
64 return FFI_BAD_TYPEDEF
;
70 ffi_prep_args (char *stack
, extended_cif
* ecif
)
73 unsigned int struct_count
= 0;
80 p_argv
= ecif
->avalue
;
82 for (i
= ecif
->cif
->nargs
, p_arg
= ecif
->cif
->arg_types
;
83 (i
!= 0); i
--, p_arg
++)
87 switch ((*p_arg
)->type
)
94 memcpy (argp
, *p_argv
, z
);
99 memcpy (argp
, *p_argv
, z
);
104 unsigned int uiLocOnStack
;
106 uiLocOnStack
= 4 * ecif
->cif
->nargs
+ struct_count
;
107 struct_count
= struct_count
+ (*p_arg
)->size
;
108 *(unsigned int *) argp
=
109 (unsigned int) (UINT32
*) (stack
+ uiLocOnStack
);
110 memcpy ((stack
+ uiLocOnStack
), *p_argv
, (*p_arg
)->size
);
116 if (z
< sizeof (int))
118 switch ((*p_arg
)->type
)
121 *(signed int *) argp
= (signed int) *(SINT8
*) (*p_argv
);
125 *(unsigned int *) argp
=
126 (unsigned int) *(UINT8
*) (*p_argv
);
129 case FFI_TYPE_SINT16
:
130 *(signed int *) argp
= (signed int) *(SINT16
*) (*p_argv
);
133 case FFI_TYPE_UINT16
:
134 *(unsigned int *) argp
=
135 (unsigned int) *(UINT16
*) (*p_argv
);
143 else if (z
== sizeof (int))
144 *(unsigned int *) argp
= (unsigned int) *(UINT32
*) (*p_argv
);
146 memcpy (argp
, *p_argv
, z
);
153 return (struct_count
);
156 ffi_status FFI_HIDDEN
157 ffi_prep_cif_core (ffi_cif
* cif
,
158 ffi_abi abi
, unsigned int isvariadic
,
159 unsigned int nfixedargs
, unsigned int ntotalargs
,
160 ffi_type
* rtype
, ffi_type
** atypes
)
166 FFI_ASSERT (cif
!= NULL
);
167 FFI_ASSERT((!isvariadic
) || (nfixedargs
>= 1));
168 FFI_ASSERT(nfixedargs
<= ntotalargs
);
169 FFI_ASSERT (abi
> FFI_FIRST_ABI
&& abi
< FFI_LAST_ABI
);
172 cif
->arg_types
= atypes
;
173 cif
->nargs
= ntotalargs
;
178 if ((cif
->rtype
->size
== 0)
179 && (initialize_aggregate_packed_struct (cif
->rtype
) != FFI_OK
))
180 return FFI_BAD_TYPEDEF
;
182 FFI_ASSERT_VALID_TYPE (cif
->rtype
);
184 for (ptr
= cif
->arg_types
, i
= cif
->nargs
; i
> 0; i
--, ptr
++)
186 if (((*ptr
)->size
== 0)
187 && (initialize_aggregate_packed_struct ((*ptr
)) != FFI_OK
))
188 return FFI_BAD_TYPEDEF
;
190 FFI_ASSERT_VALID_TYPE (*ptr
);
192 if (((*ptr
)->alignment
- 1) & bytes
)
193 bytes
= ALIGN (bytes
, (*ptr
)->alignment
);
194 if ((*ptr
)->type
== FFI_TYPE_STRUCT
)
196 if ((*ptr
)->size
> 8)
198 bytes
+= (*ptr
)->size
;
199 bytes
+= sizeof (void *);
203 if ((*ptr
)->size
> 4)
210 bytes
+= STACK_ARG_SIZE ((*ptr
)->size
);
215 return ffi_prep_cif_machdep (cif
);
219 ffi_prep_cif_machdep (ffi_cif
* cif
)
221 switch (cif
->rtype
->type
)
224 case FFI_TYPE_STRUCT
:
226 case FFI_TYPE_DOUBLE
:
227 case FFI_TYPE_SINT64
:
228 case FFI_TYPE_UINT64
:
229 cif
->flags
= (unsigned) cif
->rtype
->type
;
233 cif
->flags
= FFI_TYPE_INT
;
240 extern void ffi_call_SYSV (int (*)(char *, extended_cif
*),
242 unsigned, unsigned, unsigned *, void (*fn
) ())
243 __attribute__ ((__visibility__ ("hidden")));
246 ffi_call (ffi_cif
* cif
, void (*fn
) (), void *rvalue
, void **avalue
)
251 ecif
.avalue
= avalue
;
253 if ((rvalue
== NULL
) && (cif
->rtype
->type
== FFI_TYPE_STRUCT
))
255 ecif
.rvalue
= alloca (cif
->rtype
->size
);
258 ecif
.rvalue
= rvalue
;
263 ffi_call_SYSV (ffi_prep_args
, &ecif
, cif
->bytes
,
264 cif
->flags
, ecif
.rvalue
, fn
);
272 /* Because the following variables are not exported outside libffi, we
275 /* Assembly code for the jump stub. */
276 extern const char ffi_cris_trampoline_template
[]
277 __attribute__ ((__visibility__ ("hidden")));
279 /* Offset into ffi_cris_trampoline_template of where to put the
280 ffi_prep_closure_inner function. */
281 extern const int ffi_cris_trampoline_fn_offset
282 __attribute__ ((__visibility__ ("hidden")));
284 /* Offset into ffi_cris_trampoline_template of where to put the
286 extern const int ffi_cris_trampoline_closure_offset
287 __attribute__ ((__visibility__ ("hidden")));
289 /* This function is sibling-called (jumped to) by the closure
290 trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
291 PARAMS[4] to simplify handling of a straddling parameter. A copy
292 of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are
293 put at the appropriate place in CLOSURE which is then executed and
294 the return value is passed back to the caller. */
296 static unsigned long long
297 ffi_prep_closure_inner (void **params
, ffi_closure
* closure
)
299 char *register_args
= (char *) params
;
300 void *struct_ret
= params
[5];
301 char *stack_args
= params
[6];
302 char *ptr
= register_args
;
303 ffi_cif
*cif
= closure
->cif
;
304 ffi_type
**arg_types
= cif
->arg_types
;
306 /* Max room needed is number of arguments as 64-bit values. */
307 void **avalue
= alloca (closure
->cif
->nargs
* sizeof(void *));
312 /* Find the address of each argument. */
313 for (i
= 0, doing_regs
= 1; i
< cif
->nargs
; i
++)
315 /* Types up to and including 8 bytes go by-value. */
316 if (arg_types
[i
]->size
<= 4)
321 else if (arg_types
[i
]->size
<= 8)
328 FFI_ASSERT (arg_types
[i
]->type
== FFI_TYPE_STRUCT
);
330 /* Passed by-reference, so copy the pointer. */
331 avalue
[i
] = *(void **) ptr
;
335 /* If we've handled more arguments than fit in registers, start
336 looking at the those passed on the stack. Step over the
337 first one if we had a straddling parameter. */
338 if (doing_regs
&& ptr
>= register_args
+ 4*4)
340 ptr
= stack_args
+ ((ptr
> register_args
+ 4*4) ? 4 : 0);
345 /* Invoke the closure. */
348 cif
->rtype
->type
== FFI_TYPE_STRUCT
349 /* The caller allocated space for the return
350 structure, and passed a pointer to this space in
354 /* We take advantage of being able to ignore that
355 the high part isn't set if the return value is
356 not in R10:R11, but in R10 only. */
359 avalue
, closure
->user_data
);
364 /* API function: Prepare the trampoline. */
367 ffi_prep_closure_loc (ffi_closure
* closure
,
369 void (*fun
)(ffi_cif
*, void *, void **, void*),
373 void *innerfn
= ffi_prep_closure_inner
;
374 FFI_ASSERT (cif
->abi
== FFI_SYSV
);
376 closure
->user_data
= user_data
;
378 memcpy (closure
->tramp
, ffi_cris_trampoline_template
,
379 FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE
);
380 memcpy (closure
->tramp
+ ffi_cris_trampoline_fn_offset
,
381 &innerfn
, sizeof (void *));
382 memcpy (closure
->tramp
+ ffi_cris_trampoline_closure_offset
,
383 &codeloc
, sizeof (void *));