• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
6 
7    CRIS Foreign Function Interface
8 
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:
16 
17    The above copyright notice and this permission notice shall be included
18    in all copies or substantial portions of the Software.
19 
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    ----------------------------------------------------------------------- */
28 
29 #include <ffi.h>
30 #include <ffi_common.h>
31 
32 #define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
33 
34 static ffi_status
initialize_aggregate_packed_struct(ffi_type * arg)35 initialize_aggregate_packed_struct (ffi_type * arg)
36 {
37   ffi_type **ptr;
38 
39   FFI_ASSERT (arg != NULL);
40 
41   FFI_ASSERT (arg->elements != NULL);
42   FFI_ASSERT (arg->size == 0);
43   FFI_ASSERT (arg->alignment == 0);
44 
45   ptr = &(arg->elements[0]);
46 
47   while ((*ptr) != NULL)
48     {
49       if (((*ptr)->size == 0)
50 	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
51 	return FFI_BAD_TYPEDEF;
52 
53       FFI_ASSERT (ffi_type_test ((*ptr)));
54 
55       arg->size += (*ptr)->size;
56 
57       arg->alignment = (arg->alignment > (*ptr)->alignment) ?
58 	arg->alignment : (*ptr)->alignment;
59 
60       ptr++;
61     }
62 
63   if (arg->size == 0)
64     return FFI_BAD_TYPEDEF;
65   else
66     return FFI_OK;
67 }
68 
69 int
ffi_prep_args(char * stack,extended_cif * ecif)70 ffi_prep_args (char *stack, extended_cif * ecif)
71 {
72   unsigned int i;
73   unsigned int struct_count = 0;
74   void **p_argv;
75   char *argp;
76   ffi_type **p_arg;
77 
78   argp = stack;
79 
80   p_argv = ecif->avalue;
81 
82   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
83        (i != 0); i--, p_arg++)
84     {
85       size_t z;
86 
87       switch ((*p_arg)->type)
88 	{
89 	case FFI_TYPE_STRUCT:
90 	  {
91 	    z = (*p_arg)->size;
92 	    if (z <= 4)
93 	      {
94 		memcpy (argp, *p_argv, z);
95 		z = 4;
96 	      }
97 	    else if (z <= 8)
98 	      {
99 		memcpy (argp, *p_argv, z);
100 		z = 8;
101 	      }
102 	    else
103 	      {
104 		unsigned int uiLocOnStack;
105 		z = sizeof (void *);
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);
111 	      }
112 	    break;
113 	  }
114 	default:
115 	  z = (*p_arg)->size;
116 	  if (z < sizeof (int))
117 	    {
118 	      switch ((*p_arg)->type)
119 		{
120 		case FFI_TYPE_SINT8:
121 		  *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
122 		  break;
123 
124 		case FFI_TYPE_UINT8:
125 		  *(unsigned int *) argp =
126 		    (unsigned int) *(UINT8 *) (*p_argv);
127 		  break;
128 
129 		case FFI_TYPE_SINT16:
130 		  *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
131 		  break;
132 
133 		case FFI_TYPE_UINT16:
134 		  *(unsigned int *) argp =
135 		    (unsigned int) *(UINT16 *) (*p_argv);
136 		  break;
137 
138 		default:
139 		  FFI_ASSERT (0);
140 		}
141 	      z = sizeof (int);
142 	    }
143 	  else if (z == sizeof (int))
144 	    *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
145 	  else
146 	    memcpy (argp, *p_argv, z);
147 	  break;
148 	}
149       p_argv++;
150       argp += z;
151     }
152 
153   return (struct_count);
154 }
155 
156 ffi_status FFI_HIDDEN
ffi_prep_cif_core(ffi_cif * cif,ffi_abi abi,unsigned int isvariadic,unsigned int nfixedargs,unsigned int ntotalargs,ffi_type * rtype,ffi_type ** atypes)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)
161 {
162   unsigned bytes = 0;
163   unsigned int i;
164   ffi_type **ptr;
165 
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);
170 
171   cif->abi = abi;
172   cif->arg_types = atypes;
173   cif->nargs = ntotalargs;
174   cif->rtype = rtype;
175 
176   cif->flags = 0;
177 
178   if ((cif->rtype->size == 0)
179       && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
180     return FFI_BAD_TYPEDEF;
181 
182   FFI_ASSERT_VALID_TYPE (cif->rtype);
183 
184   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
185     {
186       if (((*ptr)->size == 0)
187 	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
188 	return FFI_BAD_TYPEDEF;
189 
190       FFI_ASSERT_VALID_TYPE (*ptr);
191 
192       if (((*ptr)->alignment - 1) & bytes)
193 	bytes = FFI_ALIGN (bytes, (*ptr)->alignment);
194       if ((*ptr)->type == FFI_TYPE_STRUCT)
195 	{
196 	  if ((*ptr)->size > 8)
197 	    {
198 	      bytes += (*ptr)->size;
199 	      bytes += sizeof (void *);
200 	    }
201 	  else
202 	    {
203 	      if ((*ptr)->size > 4)
204 		bytes += 8;
205 	      else
206 		bytes += 4;
207 	    }
208 	}
209       else
210 	bytes += STACK_ARG_SIZE ((*ptr)->size);
211     }
212 
213   cif->bytes = bytes;
214 
215   return ffi_prep_cif_machdep (cif);
216 }
217 
218 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)219 ffi_prep_cif_machdep (ffi_cif * cif)
220 {
221   switch (cif->rtype->type)
222     {
223     case FFI_TYPE_VOID:
224     case FFI_TYPE_STRUCT:
225     case FFI_TYPE_FLOAT:
226     case FFI_TYPE_DOUBLE:
227     case FFI_TYPE_SINT64:
228     case FFI_TYPE_UINT64:
229       cif->flags = (unsigned) cif->rtype->type;
230       break;
231 
232     default:
233       cif->flags = FFI_TYPE_INT;
234       break;
235     }
236 
237   return FFI_OK;
238 }
239 
240 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
241 			   extended_cif *,
242 			   unsigned, unsigned, unsigned *, void (*fn) ())
243      __attribute__ ((__visibility__ ("hidden")));
244 
245 void
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)246 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
247 {
248   extended_cif ecif;
249 
250   ecif.cif = cif;
251   ecif.avalue = avalue;
252 
253   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
254     {
255       ecif.rvalue = alloca (cif->rtype->size);
256     }
257   else
258     ecif.rvalue = rvalue;
259 
260   switch (cif->abi)
261     {
262     case FFI_SYSV:
263       ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
264 		     cif->flags, ecif.rvalue, fn);
265       break;
266     default:
267       FFI_ASSERT (0);
268       break;
269     }
270 }
271 
272 /* Because the following variables are not exported outside libffi, we
273    mark them hidden.  */
274 
275 /* Assembly code for the jump stub.  */
276 extern const char ffi_cris_trampoline_template[]
277  __attribute__ ((__visibility__ ("hidden")));
278 
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")));
283 
284 /* Offset into ffi_cris_trampoline_template of where to put the
285    closure data.  */
286 extern const int ffi_cris_trampoline_closure_offset
287  __attribute__ ((__visibility__ ("hidden")));
288 
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.  */
295 
296 static unsigned long long
ffi_prep_closure_inner(void ** params,ffi_closure * closure)297 ffi_prep_closure_inner (void **params, ffi_closure* closure)
298 {
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;
305 
306   /* Max room needed is number of arguments as 64-bit values.  */
307   void **avalue = alloca (closure->cif->nargs * sizeof(void *));
308   int i;
309   int doing_regs;
310   long long llret = 0;
311 
312   /* Find the address of each argument.  */
313   for (i = 0, doing_regs = 1; i < cif->nargs; i++)
314     {
315       /* Types up to and including 8 bytes go by-value.  */
316       if (arg_types[i]->size <= 4)
317 	{
318 	  avalue[i] = ptr;
319 	  ptr += 4;
320 	}
321       else if (arg_types[i]->size <= 8)
322 	{
323 	  avalue[i] = ptr;
324 	  ptr += 8;
325 	}
326       else
327 	{
328 	  FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
329 
330 	  /* Passed by-reference, so copy the pointer.  */
331 	  avalue[i] = *(void **) ptr;
332 	  ptr += 4;
333 	}
334 
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)
339 	{
340 	  ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
341 	  doing_regs = 0;
342 	}
343     }
344 
345   /* Invoke the closure.  */
346   (closure->fun) (cif,
347 
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
351 		     R9.  */
352 		  ? struct_ret
353 
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.  */
357 		  : (void *) &llret,
358 
359 		  avalue, closure->user_data);
360 
361   return llret;
362 }
363 
364 /* API function: Prepare the trampoline.  */
365 
366 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)367 ffi_prep_closure_loc (ffi_closure* closure,
368 		      ffi_cif* cif,
369 		      void (*fun)(ffi_cif *, void *, void **, void*),
370 		      void *user_data,
371 		      void *codeloc)
372 {
373   void *innerfn = ffi_prep_closure_inner;
374   FFI_ASSERT (cif->abi == FFI_SYSV);
375   closure->cif  = cif;
376   closure->user_data = user_data;
377   closure->fun  = fun;
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 *));
384 
385   return FFI_OK;
386 }
387