ffi.c revision 056e203a7aec4c87c077192ad776b532a3d0305f
1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (c) 1998 Cygnus Solutions
3           Copyright (c) 2004 Simon Posnjak
4	   Copyright (c) 2005 Axis Communications AB
5
6   CRIS Foreign Function Interface
7
8   Permission is hereby granted, free of charge, to any person obtaining
9   a copy of this software and associated documentation files (the
10   ``Software''), to deal in the Software without restriction, including
11   without limitation the rights to use, copy, modify, merge, publish,
12   distribute, sublicense, and/or sell copies of the Software, and to
13   permit persons to whom the Software is furnished to do so, subject to
14   the following conditions:
15
16   The above copyright notice and this permission notice shall be included
17   in all copies or substantial portions of the Software.
18
19   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
20   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22   IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
23   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25   OTHER DEALINGS IN THE SOFTWARE.
26   ----------------------------------------------------------------------- */
27
28#include <ffi.h>
29#include <ffi_common.h>
30
31#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
32
33static ffi_status
34initialize_aggregate_packed_struct (ffi_type * arg)
35{
36  ffi_type **ptr;
37
38  FFI_ASSERT (arg != NULL);
39
40  FFI_ASSERT (arg->elements != NULL);
41  FFI_ASSERT (arg->size == 0);
42  FFI_ASSERT (arg->alignment == 0);
43
44  ptr = &(arg->elements[0]);
45
46  while ((*ptr) != NULL)
47    {
48      if (((*ptr)->size == 0)
49	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
50	return FFI_BAD_TYPEDEF;
51
52      FFI_ASSERT (ffi_type_test ((*ptr)));
53
54      arg->size += (*ptr)->size;
55
56      arg->alignment = (arg->alignment > (*ptr)->alignment) ?
57	arg->alignment : (*ptr)->alignment;
58
59      ptr++;
60    }
61
62  if (arg->size == 0)
63    return FFI_BAD_TYPEDEF;
64  else
65    return FFI_OK;
66}
67
68int
69ffi_prep_args (char *stack, extended_cif * ecif)
70{
71  unsigned int i;
72  unsigned int struct_count = 0;
73  void **p_argv;
74  char *argp;
75  ffi_type **p_arg;
76
77  argp = stack;
78
79  p_argv = ecif->avalue;
80
81  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
82       (i != 0); i--, p_arg++)
83    {
84      size_t z;
85
86      switch ((*p_arg)->type)
87	{
88	case FFI_TYPE_STRUCT:
89	  {
90	    z = (*p_arg)->size;
91	    if (z <= 4)
92	      {
93		memcpy (argp, *p_argv, z);
94		z = 4;
95	      }
96	    else if (z <= 8)
97	      {
98		memcpy (argp, *p_argv, z);
99		z = 8;
100	      }
101	    else
102	      {
103		unsigned int uiLocOnStack;
104		z = sizeof (void *);
105		uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
106		struct_count = struct_count + (*p_arg)->size;
107		*(unsigned int *) argp =
108		  (unsigned int) (UINT32 *) (stack + uiLocOnStack);
109		memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
110	      }
111	    break;
112	  }
113	default:
114	  z = (*p_arg)->size;
115	  if (z < sizeof (int))
116	    {
117	      switch ((*p_arg)->type)
118		{
119		case FFI_TYPE_SINT8:
120		  *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
121		  break;
122
123		case FFI_TYPE_UINT8:
124		  *(unsigned int *) argp =
125		    (unsigned int) *(UINT8 *) (*p_argv);
126		  break;
127
128		case FFI_TYPE_SINT16:
129		  *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
130		  break;
131
132		case FFI_TYPE_UINT16:
133		  *(unsigned int *) argp =
134		    (unsigned int) *(UINT16 *) (*p_argv);
135		  break;
136
137		default:
138		  FFI_ASSERT (0);
139		}
140	      z = sizeof (int);
141	    }
142	  else if (z == sizeof (int))
143	    *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
144	  else
145	    memcpy (argp, *p_argv, z);
146	  break;
147	}
148      p_argv++;
149      argp += z;
150    }
151
152  return (struct_count);
153}
154
155ffi_status
156ffi_prep_cif (ffi_cif * cif,
157	      ffi_abi abi, unsigned int nargs,
158	      ffi_type * rtype, ffi_type ** atypes)
159{
160  unsigned bytes = 0;
161  unsigned int i;
162  ffi_type **ptr;
163
164  FFI_ASSERT (cif != NULL);
165  FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
166
167  cif->abi = abi;
168  cif->arg_types = atypes;
169  cif->nargs = nargs;
170  cif->rtype = rtype;
171
172  cif->flags = 0;
173
174  if ((cif->rtype->size == 0)
175      && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
176    return FFI_BAD_TYPEDEF;
177
178  FFI_ASSERT_VALID_TYPE (cif->rtype);
179
180  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
181    {
182      if (((*ptr)->size == 0)
183	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
184	return FFI_BAD_TYPEDEF;
185
186      FFI_ASSERT_VALID_TYPE (*ptr);
187
188      if (((*ptr)->alignment - 1) & bytes)
189	bytes = ALIGN (bytes, (*ptr)->alignment);
190      if ((*ptr)->type == FFI_TYPE_STRUCT)
191	{
192	  if ((*ptr)->size > 8)
193	    {
194	      bytes += (*ptr)->size;
195	      bytes += sizeof (void *);
196	    }
197	  else
198	    {
199	      if ((*ptr)->size > 4)
200		bytes += 8;
201	      else
202		bytes += 4;
203	    }
204	}
205      else
206	bytes += STACK_ARG_SIZE ((*ptr)->size);
207    }
208
209  cif->bytes = bytes;
210
211  return ffi_prep_cif_machdep (cif);
212}
213
214ffi_status
215ffi_prep_cif_machdep (ffi_cif * cif)
216{
217  switch (cif->rtype->type)
218    {
219    case FFI_TYPE_VOID:
220    case FFI_TYPE_STRUCT:
221    case FFI_TYPE_FLOAT:
222    case FFI_TYPE_DOUBLE:
223    case FFI_TYPE_SINT64:
224    case FFI_TYPE_UINT64:
225      cif->flags = (unsigned) cif->rtype->type;
226      break;
227
228    default:
229      cif->flags = FFI_TYPE_INT;
230      break;
231    }
232
233  return FFI_OK;
234}
235
236extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
237			   extended_cif *,
238			   unsigned, unsigned, unsigned *, void (*fn) ())
239     __attribute__ ((__visibility__ ("hidden")));
240
241void
242ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
243{
244  extended_cif ecif;
245
246  ecif.cif = cif;
247  ecif.avalue = avalue;
248
249  if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
250    {
251      ecif.rvalue = alloca (cif->rtype->size);
252    }
253  else
254    ecif.rvalue = rvalue;
255
256  switch (cif->abi)
257    {
258    case FFI_SYSV:
259      ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
260		     cif->flags, ecif.rvalue, fn);
261      break;
262    default:
263      FFI_ASSERT (0);
264      break;
265    }
266}
267
268/* Because the following variables are not exported outside libffi, we
269   mark them hidden.  */
270
271/* Assembly code for the jump stub.  */
272extern const char ffi_cris_trampoline_template[]
273 __attribute__ ((__visibility__ ("hidden")));
274
275/* Offset into ffi_cris_trampoline_template of where to put the
276   ffi_prep_closure_inner function.  */
277extern const int ffi_cris_trampoline_fn_offset
278 __attribute__ ((__visibility__ ("hidden")));
279
280/* Offset into ffi_cris_trampoline_template of where to put the
281   closure data.  */
282extern const int ffi_cris_trampoline_closure_offset
283 __attribute__ ((__visibility__ ("hidden")));
284
285/* This function is sibling-called (jumped to) by the closure
286   trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
287   PARAMS[4] to simplify handling of a straddling parameter.  A copy
288   of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
289   put at the appropriate place in CLOSURE which is then executed and
290   the return value is passed back to the caller.  */
291
292static unsigned long long
293ffi_prep_closure_inner (void **params, ffi_closure* closure)
294{
295  char *register_args = (char *) params;
296  void *struct_ret = params[5];
297  char *stack_args = params[6];
298  char *ptr = register_args;
299  ffi_cif *cif = closure->cif;
300  ffi_type **arg_types = cif->arg_types;
301
302  /* Max room needed is number of arguments as 64-bit values.  */
303  void **avalue = alloca (closure->cif->nargs * sizeof(void *));
304  int i;
305  int doing_regs;
306  long long llret = 0;
307
308  /* Find the address of each argument.  */
309  for (i = 0, doing_regs = 1; i < cif->nargs; i++)
310    {
311      /* Types up to and including 8 bytes go by-value.  */
312      if (arg_types[i]->size <= 4)
313	{
314	  avalue[i] = ptr;
315	  ptr += 4;
316	}
317      else if (arg_types[i]->size <= 8)
318	{
319	  avalue[i] = ptr;
320	  ptr += 8;
321	}
322      else
323	{
324	  FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
325
326	  /* Passed by-reference, so copy the pointer.  */
327	  avalue[i] = *(void **) ptr;
328	  ptr += 4;
329	}
330
331      /* If we've handled more arguments than fit in registers, start
332	 looking at the those passed on the stack.  Step over the
333	 first one if we had a straddling parameter.  */
334      if (doing_regs && ptr >= register_args + 4*4)
335	{
336	  ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
337	  doing_regs = 0;
338	}
339    }
340
341  /* Invoke the closure.  */
342  (closure->fun) (cif,
343
344		  cif->rtype->type == FFI_TYPE_STRUCT
345		  /* The caller allocated space for the return
346		     structure, and passed a pointer to this space in
347		     R9.  */
348		  ? struct_ret
349
350		  /* We take advantage of being able to ignore that
351		     the high part isn't set if the return value is
352		     not in R10:R11, but in R10 only.  */
353		  : (void *) &llret,
354
355		  avalue, closure->user_data);
356
357  return llret;
358}
359
360/* API function: Prepare the trampoline.  */
361
362ffi_status
363ffi_prep_closure (ffi_closure* closure,
364		  ffi_cif* cif,
365		  void (*fun)(ffi_cif *, void *, void **, void*),
366		  void *user_data)
367{
368  void *innerfn = ffi_prep_closure_inner;
369  FFI_ASSERT (cif->abi == FFI_SYSV);
370  closure->cif  = cif;
371  closure->user_data = user_data;
372  closure->fun  = fun;
373  memcpy (closure->tramp, ffi_cris_trampoline_template,
374	  FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
375  memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
376	  &innerfn, sizeof (void *));
377  memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
378	  &closure, sizeof (void *));
379
380  return FFI_OK;
381}
382