xref: /aosp_15_r20/external/libffi/src/moxie/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi.c - Copyright (C) 2012, 2013, 2018  Anthony Green
3*1fd5a2e1SPrashanth Swaminathan 
4*1fd5a2e1SPrashanth Swaminathan    Moxie Foreign Function Interface
5*1fd5a2e1SPrashanth Swaminathan 
6*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
7*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
8*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
9*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
10*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
11*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
12*1fd5a2e1SPrashanth Swaminathan    the following conditions:
13*1fd5a2e1SPrashanth Swaminathan 
14*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
15*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
16*1fd5a2e1SPrashanth Swaminathan 
17*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18*1fd5a2e1SPrashanth Swaminathan    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20*1fd5a2e1SPrashanth Swaminathan    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21*1fd5a2e1SPrashanth Swaminathan    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22*1fd5a2e1SPrashanth Swaminathan    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*1fd5a2e1SPrashanth Swaminathan    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24*1fd5a2e1SPrashanth Swaminathan    DEALINGS IN THE SOFTWARE.
25*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
26*1fd5a2e1SPrashanth Swaminathan 
27*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
28*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
29*1fd5a2e1SPrashanth Swaminathan 
30*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
31*1fd5a2e1SPrashanth Swaminathan 
32*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack space
33*1fd5a2e1SPrashanth Swaminathan    has been allocated for the function's arguments */
34*1fd5a2e1SPrashanth Swaminathan 
ffi_prep_args(char * stack,extended_cif * ecif)35*1fd5a2e1SPrashanth Swaminathan void *ffi_prep_args(char *stack, extended_cif *ecif)
36*1fd5a2e1SPrashanth Swaminathan {
37*1fd5a2e1SPrashanth Swaminathan   register unsigned int i;
38*1fd5a2e1SPrashanth Swaminathan   register void **p_argv;
39*1fd5a2e1SPrashanth Swaminathan   register char *argp;
40*1fd5a2e1SPrashanth Swaminathan   register ffi_type **p_arg;
41*1fd5a2e1SPrashanth Swaminathan   register int count = 0;
42*1fd5a2e1SPrashanth Swaminathan 
43*1fd5a2e1SPrashanth Swaminathan   p_argv = ecif->avalue;
44*1fd5a2e1SPrashanth Swaminathan   argp = stack;
45*1fd5a2e1SPrashanth Swaminathan 
46*1fd5a2e1SPrashanth Swaminathan   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
47*1fd5a2e1SPrashanth Swaminathan     {
48*1fd5a2e1SPrashanth Swaminathan       *(void **) argp = ecif->rvalue;
49*1fd5a2e1SPrashanth Swaminathan       argp += 4;
50*1fd5a2e1SPrashanth Swaminathan     }
51*1fd5a2e1SPrashanth Swaminathan 
52*1fd5a2e1SPrashanth Swaminathan   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
53*1fd5a2e1SPrashanth Swaminathan        (i != 0);
54*1fd5a2e1SPrashanth Swaminathan        i--, p_arg++)
55*1fd5a2e1SPrashanth Swaminathan     {
56*1fd5a2e1SPrashanth Swaminathan       size_t z;
57*1fd5a2e1SPrashanth Swaminathan 
58*1fd5a2e1SPrashanth Swaminathan       z = (*p_arg)->size;
59*1fd5a2e1SPrashanth Swaminathan 
60*1fd5a2e1SPrashanth Swaminathan       if ((*p_arg)->type == FFI_TYPE_STRUCT)
61*1fd5a2e1SPrashanth Swaminathan 	{
62*1fd5a2e1SPrashanth Swaminathan 	  z = sizeof(void*);
63*1fd5a2e1SPrashanth Swaminathan 	  *(void **) argp = *p_argv;
64*1fd5a2e1SPrashanth Swaminathan 	}
65*1fd5a2e1SPrashanth Swaminathan       else if (z < sizeof(int))
66*1fd5a2e1SPrashanth Swaminathan 	{
67*1fd5a2e1SPrashanth Swaminathan 	  z = sizeof(int);
68*1fd5a2e1SPrashanth Swaminathan 	  switch ((*p_arg)->type)
69*1fd5a2e1SPrashanth Swaminathan 	    {
70*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_SINT8:
71*1fd5a2e1SPrashanth Swaminathan 	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
72*1fd5a2e1SPrashanth Swaminathan 	      break;
73*1fd5a2e1SPrashanth Swaminathan 
74*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_UINT8:
75*1fd5a2e1SPrashanth Swaminathan 	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
76*1fd5a2e1SPrashanth Swaminathan 	      break;
77*1fd5a2e1SPrashanth Swaminathan 
78*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_SINT16:
79*1fd5a2e1SPrashanth Swaminathan 	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
80*1fd5a2e1SPrashanth Swaminathan 	      break;
81*1fd5a2e1SPrashanth Swaminathan 
82*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_UINT16:
83*1fd5a2e1SPrashanth Swaminathan 	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
84*1fd5a2e1SPrashanth Swaminathan 	      break;
85*1fd5a2e1SPrashanth Swaminathan 
86*1fd5a2e1SPrashanth Swaminathan 	    default:
87*1fd5a2e1SPrashanth Swaminathan 	      FFI_ASSERT(0);
88*1fd5a2e1SPrashanth Swaminathan 	    }
89*1fd5a2e1SPrashanth Swaminathan 	}
90*1fd5a2e1SPrashanth Swaminathan       else if (z == sizeof(int))
91*1fd5a2e1SPrashanth Swaminathan 	{
92*1fd5a2e1SPrashanth Swaminathan 	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
93*1fd5a2e1SPrashanth Swaminathan 	}
94*1fd5a2e1SPrashanth Swaminathan       else
95*1fd5a2e1SPrashanth Swaminathan 	{
96*1fd5a2e1SPrashanth Swaminathan 	  memcpy(argp, *p_argv, z);
97*1fd5a2e1SPrashanth Swaminathan 	}
98*1fd5a2e1SPrashanth Swaminathan       p_argv++;
99*1fd5a2e1SPrashanth Swaminathan       argp += z;
100*1fd5a2e1SPrashanth Swaminathan       count += z;
101*1fd5a2e1SPrashanth Swaminathan     }
102*1fd5a2e1SPrashanth Swaminathan 
103*1fd5a2e1SPrashanth Swaminathan   return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
104*1fd5a2e1SPrashanth Swaminathan }
105*1fd5a2e1SPrashanth Swaminathan 
106*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)107*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
108*1fd5a2e1SPrashanth Swaminathan {
109*1fd5a2e1SPrashanth Swaminathan   if (cif->rtype->type == FFI_TYPE_STRUCT)
110*1fd5a2e1SPrashanth Swaminathan     cif->flags = -1;
111*1fd5a2e1SPrashanth Swaminathan   else
112*1fd5a2e1SPrashanth Swaminathan     cif->flags = cif->rtype->size;
113*1fd5a2e1SPrashanth Swaminathan 
114*1fd5a2e1SPrashanth Swaminathan   cif->bytes = FFI_ALIGN (cif->bytes, 8);
115*1fd5a2e1SPrashanth Swaminathan 
116*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
117*1fd5a2e1SPrashanth Swaminathan }
118*1fd5a2e1SPrashanth Swaminathan 
119*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
120*1fd5a2e1SPrashanth Swaminathan 			  extended_cif *,
121*1fd5a2e1SPrashanth Swaminathan 			  unsigned, unsigned,
122*1fd5a2e1SPrashanth Swaminathan 			  unsigned *,
123*1fd5a2e1SPrashanth Swaminathan 			  void (*fn)(void));
124*1fd5a2e1SPrashanth Swaminathan 
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)125*1fd5a2e1SPrashanth Swaminathan void ffi_call(ffi_cif *cif,
126*1fd5a2e1SPrashanth Swaminathan 	      void (*fn)(void),
127*1fd5a2e1SPrashanth Swaminathan 	      void *rvalue,
128*1fd5a2e1SPrashanth Swaminathan 	      void **avalue)
129*1fd5a2e1SPrashanth Swaminathan {
130*1fd5a2e1SPrashanth Swaminathan   extended_cif ecif;
131*1fd5a2e1SPrashanth Swaminathan 
132*1fd5a2e1SPrashanth Swaminathan   ecif.cif = cif;
133*1fd5a2e1SPrashanth Swaminathan   ecif.avalue = avalue;
134*1fd5a2e1SPrashanth Swaminathan 
135*1fd5a2e1SPrashanth Swaminathan   /* If the return value is a struct and we don't have a return	*/
136*1fd5a2e1SPrashanth Swaminathan   /* value address then we need to make one		        */
137*1fd5a2e1SPrashanth Swaminathan 
138*1fd5a2e1SPrashanth Swaminathan   if ((rvalue == NULL) &&
139*1fd5a2e1SPrashanth Swaminathan       (cif->rtype->type == FFI_TYPE_STRUCT))
140*1fd5a2e1SPrashanth Swaminathan     {
141*1fd5a2e1SPrashanth Swaminathan       ecif.rvalue = alloca(cif->rtype->size);
142*1fd5a2e1SPrashanth Swaminathan     }
143*1fd5a2e1SPrashanth Swaminathan   else
144*1fd5a2e1SPrashanth Swaminathan     ecif.rvalue = rvalue;
145*1fd5a2e1SPrashanth Swaminathan 
146*1fd5a2e1SPrashanth Swaminathan   switch (cif->abi)
147*1fd5a2e1SPrashanth Swaminathan     {
148*1fd5a2e1SPrashanth Swaminathan     case FFI_EABI:
149*1fd5a2e1SPrashanth Swaminathan       ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
150*1fd5a2e1SPrashanth Swaminathan 		    cif->flags, ecif.rvalue, fn);
151*1fd5a2e1SPrashanth Swaminathan       break;
152*1fd5a2e1SPrashanth Swaminathan     default:
153*1fd5a2e1SPrashanth Swaminathan       FFI_ASSERT(0);
154*1fd5a2e1SPrashanth Swaminathan       break;
155*1fd5a2e1SPrashanth Swaminathan     }
156*1fd5a2e1SPrashanth Swaminathan }
157*1fd5a2e1SPrashanth Swaminathan 
ffi_closure_eabi(unsigned arg1,unsigned arg2,unsigned arg3,unsigned arg4,unsigned arg5,unsigned arg6)158*1fd5a2e1SPrashanth Swaminathan void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
159*1fd5a2e1SPrashanth Swaminathan 		       unsigned arg4, unsigned arg5, unsigned arg6)
160*1fd5a2e1SPrashanth Swaminathan {
161*1fd5a2e1SPrashanth Swaminathan   /* This function is called by a trampoline.  The trampoline stows a
162*1fd5a2e1SPrashanth Swaminathan      pointer to the ffi_closure object in $r12.  We must save this
163*1fd5a2e1SPrashanth Swaminathan      pointer in a place that will persist while we do our work.  */
164*1fd5a2e1SPrashanth Swaminathan   register ffi_closure *creg __asm__ ("$r12");
165*1fd5a2e1SPrashanth Swaminathan   ffi_closure *closure = creg;
166*1fd5a2e1SPrashanth Swaminathan 
167*1fd5a2e1SPrashanth Swaminathan   /* Arguments that don't fit in registers are found on the stack
168*1fd5a2e1SPrashanth Swaminathan      at a fixed offset above the current frame pointer.  */
169*1fd5a2e1SPrashanth Swaminathan   register char *frame_pointer __asm__ ("$fp");
170*1fd5a2e1SPrashanth Swaminathan 
171*1fd5a2e1SPrashanth Swaminathan   /* Pointer to a struct return value.  */
172*1fd5a2e1SPrashanth Swaminathan   void *struct_rvalue = (void *) arg1;
173*1fd5a2e1SPrashanth Swaminathan 
174*1fd5a2e1SPrashanth Swaminathan   /* 6 words reserved for register args + 3 words from jsr */
175*1fd5a2e1SPrashanth Swaminathan   char *stack_args = frame_pointer + 9*4;
176*1fd5a2e1SPrashanth Swaminathan 
177*1fd5a2e1SPrashanth Swaminathan   /* Lay the register arguments down in a continuous chunk of memory.  */
178*1fd5a2e1SPrashanth Swaminathan   unsigned register_args[6] =
179*1fd5a2e1SPrashanth Swaminathan     { arg1, arg2, arg3, arg4, arg5, arg6 };
180*1fd5a2e1SPrashanth Swaminathan   char *register_args_ptr = (char *) register_args;
181*1fd5a2e1SPrashanth Swaminathan 
182*1fd5a2e1SPrashanth Swaminathan   ffi_cif *cif = closure->cif;
183*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types = cif->arg_types;
184*1fd5a2e1SPrashanth Swaminathan   void **avalue = alloca (cif->nargs * sizeof(void *));
185*1fd5a2e1SPrashanth Swaminathan   char *ptr = (char *) register_args;
186*1fd5a2e1SPrashanth Swaminathan   int i;
187*1fd5a2e1SPrashanth Swaminathan 
188*1fd5a2e1SPrashanth Swaminathan   /* preserve struct type return pointer passing */
189*1fd5a2e1SPrashanth Swaminathan   if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
190*1fd5a2e1SPrashanth Swaminathan     ptr += 4;
191*1fd5a2e1SPrashanth Swaminathan     register_args_ptr = (char *)&register_args[1];
192*1fd5a2e1SPrashanth Swaminathan   }
193*1fd5a2e1SPrashanth Swaminathan 
194*1fd5a2e1SPrashanth Swaminathan   /* Find the address of each argument.  */
195*1fd5a2e1SPrashanth Swaminathan   for (i = 0; i < cif->nargs; i++)
196*1fd5a2e1SPrashanth Swaminathan     {
197*1fd5a2e1SPrashanth Swaminathan       switch (arg_types[i]->type)
198*1fd5a2e1SPrashanth Swaminathan 	{
199*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
200*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
201*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = ptr + 3;
202*1fd5a2e1SPrashanth Swaminathan 	  break;
203*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
204*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
205*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = ptr + 2;
206*1fd5a2e1SPrashanth Swaminathan 	  break;
207*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
208*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
209*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
210*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
211*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = ptr;
212*1fd5a2e1SPrashanth Swaminathan 	  break;
213*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
214*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = *(void**)ptr;
215*1fd5a2e1SPrashanth Swaminathan 	  break;
216*1fd5a2e1SPrashanth Swaminathan 	default:
217*1fd5a2e1SPrashanth Swaminathan 	  /* This is an 8-byte value.  */
218*1fd5a2e1SPrashanth Swaminathan 	  if (ptr == (char *) &register_args[5])
219*1fd5a2e1SPrashanth Swaminathan 	    {
220*1fd5a2e1SPrashanth Swaminathan 	      /* The value is split across two locations */
221*1fd5a2e1SPrashanth Swaminathan 	      unsigned *ip = alloca(8);
222*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = ip;
223*1fd5a2e1SPrashanth Swaminathan 	      ip[0] = *(unsigned *) ptr;
224*1fd5a2e1SPrashanth Swaminathan 	      ip[1] = *(unsigned *) stack_args;
225*1fd5a2e1SPrashanth Swaminathan 	    }
226*1fd5a2e1SPrashanth Swaminathan 	  else
227*1fd5a2e1SPrashanth Swaminathan 	    {
228*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = ptr;
229*1fd5a2e1SPrashanth Swaminathan 	    }
230*1fd5a2e1SPrashanth Swaminathan 	  ptr += 4;
231*1fd5a2e1SPrashanth Swaminathan 	  break;
232*1fd5a2e1SPrashanth Swaminathan 	}
233*1fd5a2e1SPrashanth Swaminathan       ptr += 4;
234*1fd5a2e1SPrashanth Swaminathan 
235*1fd5a2e1SPrashanth Swaminathan       /* If we've handled more arguments than fit in registers,
236*1fd5a2e1SPrashanth Swaminathan 	 start looking at the those passed on the stack.  */
237*1fd5a2e1SPrashanth Swaminathan       if (ptr == (char *) &register_args[6])
238*1fd5a2e1SPrashanth Swaminathan 	ptr = stack_args;
239*1fd5a2e1SPrashanth Swaminathan       else if (ptr == (char *) &register_args[7])
240*1fd5a2e1SPrashanth Swaminathan 	ptr = stack_args + 4;
241*1fd5a2e1SPrashanth Swaminathan     }
242*1fd5a2e1SPrashanth Swaminathan 
243*1fd5a2e1SPrashanth Swaminathan   /* Invoke the closure.  */
244*1fd5a2e1SPrashanth Swaminathan   if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
245*1fd5a2e1SPrashanth Swaminathan     {
246*1fd5a2e1SPrashanth Swaminathan       (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
247*1fd5a2e1SPrashanth Swaminathan     }
248*1fd5a2e1SPrashanth Swaminathan   else
249*1fd5a2e1SPrashanth Swaminathan     {
250*1fd5a2e1SPrashanth Swaminathan       /* Allocate space for the return value and call the function.  */
251*1fd5a2e1SPrashanth Swaminathan       long long rvalue;
252*1fd5a2e1SPrashanth Swaminathan       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
253*1fd5a2e1SPrashanth Swaminathan       asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue));
254*1fd5a2e1SPrashanth Swaminathan     }
255*1fd5a2e1SPrashanth Swaminathan }
256*1fd5a2e1SPrashanth Swaminathan 
257*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)258*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure* closure,
259*1fd5a2e1SPrashanth Swaminathan 		      ffi_cif* cif,
260*1fd5a2e1SPrashanth Swaminathan 		      void (*fun)(ffi_cif*, void*, void**, void*),
261*1fd5a2e1SPrashanth Swaminathan 		      void *user_data,
262*1fd5a2e1SPrashanth Swaminathan 		      void *codeloc)
263*1fd5a2e1SPrashanth Swaminathan {
264*1fd5a2e1SPrashanth Swaminathan   unsigned short *tramp = (unsigned short *) &closure->tramp[0];
265*1fd5a2e1SPrashanth Swaminathan   unsigned long fn = (long) ffi_closure_eabi;
266*1fd5a2e1SPrashanth Swaminathan   unsigned long cls = (long) codeloc;
267*1fd5a2e1SPrashanth Swaminathan 
268*1fd5a2e1SPrashanth Swaminathan   if (cif->abi != FFI_EABI)
269*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
270*1fd5a2e1SPrashanth Swaminathan 
271*1fd5a2e1SPrashanth Swaminathan   fn = (unsigned long) ffi_closure_eabi;
272*1fd5a2e1SPrashanth Swaminathan 
273*1fd5a2e1SPrashanth Swaminathan   tramp[0] = 0x01e0; /* ldi.l $r12, .... */
274*1fd5a2e1SPrashanth Swaminathan   tramp[1] = cls >> 16;
275*1fd5a2e1SPrashanth Swaminathan   tramp[2] = cls & 0xffff;
276*1fd5a2e1SPrashanth Swaminathan   tramp[3] = 0x1a00; /* jmpa .... */
277*1fd5a2e1SPrashanth Swaminathan   tramp[4] = fn >> 16;
278*1fd5a2e1SPrashanth Swaminathan   tramp[5] = fn & 0xffff;
279*1fd5a2e1SPrashanth Swaminathan 
280*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
281*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
282*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
283*1fd5a2e1SPrashanth Swaminathan 
284*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
285*1fd5a2e1SPrashanth Swaminathan }
286