• 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) 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_prep_cif(ffi_cif * cif,ffi_abi abi,unsigned int nargs,ffi_type * rtype,ffi_type ** atypes)157 ffi_prep_cif (ffi_cif * cif,
158 	      ffi_abi abi, unsigned int nargs,
159 	      ffi_type * rtype, ffi_type ** atypes)
160 {
161   unsigned bytes = 0;
162   unsigned int i;
163   ffi_type **ptr;
164 
165   FFI_ASSERT (cif != NULL);
166   FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
167 
168   cif->abi = abi;
169   cif->arg_types = atypes;
170   cif->nargs = nargs;
171   cif->rtype = rtype;
172 
173   cif->flags = 0;
174 
175   if ((cif->rtype->size == 0)
176       && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
177     return FFI_BAD_TYPEDEF;
178 
179   FFI_ASSERT_VALID_TYPE (cif->rtype);
180 
181   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
182     {
183       if (((*ptr)->size == 0)
184 	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
185 	return FFI_BAD_TYPEDEF;
186 
187       FFI_ASSERT_VALID_TYPE (*ptr);
188 
189       if (((*ptr)->alignment - 1) & bytes)
190 	bytes = ALIGN (bytes, (*ptr)->alignment);
191       if ((*ptr)->type == FFI_TYPE_STRUCT)
192 	{
193 	  if ((*ptr)->size > 8)
194 	    {
195 	      bytes += (*ptr)->size;
196 	      bytes += sizeof (void *);
197 	    }
198 	  else
199 	    {
200 	      if ((*ptr)->size > 4)
201 		bytes += 8;
202 	      else
203 		bytes += 4;
204 	    }
205 	}
206       else
207 	bytes += STACK_ARG_SIZE ((*ptr)->size);
208     }
209 
210   cif->bytes = bytes;
211 
212   return ffi_prep_cif_machdep (cif);
213 }
214 
215 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)216 ffi_prep_cif_machdep (ffi_cif * cif)
217 {
218   switch (cif->rtype->type)
219     {
220     case FFI_TYPE_VOID:
221     case FFI_TYPE_STRUCT:
222     case FFI_TYPE_FLOAT:
223     case FFI_TYPE_DOUBLE:
224     case FFI_TYPE_SINT64:
225     case FFI_TYPE_UINT64:
226       cif->flags = (unsigned) cif->rtype->type;
227       break;
228 
229     default:
230       cif->flags = FFI_TYPE_INT;
231       break;
232     }
233 
234   return FFI_OK;
235 }
236 
237 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
238 			   extended_cif *,
239 			   unsigned, unsigned, unsigned *, void (*fn) ())
240      __attribute__ ((__visibility__ ("hidden")));
241 
242 void
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)243 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
244 {
245   extended_cif ecif;
246 
247   ecif.cif = cif;
248   ecif.avalue = avalue;
249 
250   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
251     {
252       ecif.rvalue = alloca (cif->rtype->size);
253     }
254   else
255     ecif.rvalue = rvalue;
256 
257   switch (cif->abi)
258     {
259     case FFI_SYSV:
260       ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
261 		     cif->flags, ecif.rvalue, fn);
262       break;
263     default:
264       FFI_ASSERT (0);
265       break;
266     }
267 }
268 
269 /* Because the following variables are not exported outside libffi, we
270    mark them hidden.  */
271 
272 /* Assembly code for the jump stub.  */
273 extern const char ffi_cris_trampoline_template[]
274  __attribute__ ((__visibility__ ("hidden")));
275 
276 /* Offset into ffi_cris_trampoline_template of where to put the
277    ffi_prep_closure_inner function.  */
278 extern const int ffi_cris_trampoline_fn_offset
279  __attribute__ ((__visibility__ ("hidden")));
280 
281 /* Offset into ffi_cris_trampoline_template of where to put the
282    closure data.  */
283 extern const int ffi_cris_trampoline_closure_offset
284  __attribute__ ((__visibility__ ("hidden")));
285 
286 /* This function is sibling-called (jumped to) by the closure
287    trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
288    PARAMS[4] to simplify handling of a straddling parameter.  A copy
289    of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
290    put at the appropriate place in CLOSURE which is then executed and
291    the return value is passed back to the caller.  */
292 
293 static unsigned long long
ffi_prep_closure_inner(void ** params,ffi_closure * closure)294 ffi_prep_closure_inner (void **params, ffi_closure* closure)
295 {
296   char *register_args = (char *) params;
297   void *struct_ret = params[5];
298   char *stack_args = params[6];
299   char *ptr = register_args;
300   ffi_cif *cif = closure->cif;
301   ffi_type **arg_types = cif->arg_types;
302 
303   /* Max room needed is number of arguments as 64-bit values.  */
304   void **avalue = alloca (closure->cif->nargs * sizeof(void *));
305   int i;
306   int doing_regs;
307   long long llret = 0;
308 
309   /* Find the address of each argument.  */
310   for (i = 0, doing_regs = 1; i < cif->nargs; i++)
311     {
312       /* Types up to and including 8 bytes go by-value.  */
313       if (arg_types[i]->size <= 4)
314 	{
315 	  avalue[i] = ptr;
316 	  ptr += 4;
317 	}
318       else if (arg_types[i]->size <= 8)
319 	{
320 	  avalue[i] = ptr;
321 	  ptr += 8;
322 	}
323       else
324 	{
325 	  FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
326 
327 	  /* Passed by-reference, so copy the pointer.  */
328 	  avalue[i] = *(void **) ptr;
329 	  ptr += 4;
330 	}
331 
332       /* If we've handled more arguments than fit in registers, start
333 	 looking at the those passed on the stack.  Step over the
334 	 first one if we had a straddling parameter.  */
335       if (doing_regs && ptr >= register_args + 4*4)
336 	{
337 	  ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
338 	  doing_regs = 0;
339 	}
340     }
341 
342   /* Invoke the closure.  */
343   (closure->fun) (cif,
344 
345 		  cif->rtype->type == FFI_TYPE_STRUCT
346 		  /* The caller allocated space for the return
347 		     structure, and passed a pointer to this space in
348 		     R9.  */
349 		  ? struct_ret
350 
351 		  /* We take advantage of being able to ignore that
352 		     the high part isn't set if the return value is
353 		     not in R10:R11, but in R10 only.  */
354 		  : (void *) &llret,
355 
356 		  avalue, closure->user_data);
357 
358   return llret;
359 }
360 
361 /* API function: Prepare the trampoline.  */
362 
363 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)364 ffi_prep_closure_loc (ffi_closure* closure,
365 		      ffi_cif* cif,
366 		      void (*fun)(ffi_cif *, void *, void **, void*),
367 		      void *user_data,
368 		      void *codeloc)
369 {
370   void *innerfn = ffi_prep_closure_inner;
371   FFI_ASSERT (cif->abi == FFI_SYSV);
372   closure->cif  = cif;
373   closure->user_data = user_data;
374   closure->fun  = fun;
375   memcpy (closure->tramp, ffi_cris_trampoline_template,
376 	  FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
377   memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
378 	  &innerfn, sizeof (void *));
379   memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
380 	  &codeloc, sizeof (void *));
381 
382   return FFI_OK;
383 }
384