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