xref: /aosp_15_r20/external/libffi/src/x86/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi.c - Copyright (c) 2017  Anthony Green
3*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc.
4*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 2002  Ranjit Mathew
5*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 2002  Bo Thorsen
6*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 2002  Roger Sayle
7*1fd5a2e1SPrashanth Swaminathan            Copyright (C) 2008, 2010  Free Software Foundation, Inc.
8*1fd5a2e1SPrashanth Swaminathan 
9*1fd5a2e1SPrashanth Swaminathan    x86 Foreign Function Interface
10*1fd5a2e1SPrashanth Swaminathan 
11*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
12*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
13*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
14*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
15*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
16*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
17*1fd5a2e1SPrashanth Swaminathan    the following conditions:
18*1fd5a2e1SPrashanth Swaminathan 
19*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
20*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
21*1fd5a2e1SPrashanth Swaminathan 
22*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
23*1fd5a2e1SPrashanth Swaminathan    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25*1fd5a2e1SPrashanth Swaminathan    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26*1fd5a2e1SPrashanth Swaminathan    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27*1fd5a2e1SPrashanth Swaminathan    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28*1fd5a2e1SPrashanth Swaminathan    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29*1fd5a2e1SPrashanth Swaminathan    DEALINGS IN THE SOFTWARE.
30*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
31*1fd5a2e1SPrashanth Swaminathan 
32*1fd5a2e1SPrashanth Swaminathan #if defined(__i386__) || defined(_M_IX86)
33*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
34*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
35*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
36*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
37*1fd5a2e1SPrashanth Swaminathan #include "internal.h"
38*1fd5a2e1SPrashanth Swaminathan 
39*1fd5a2e1SPrashanth Swaminathan /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
40*1fd5a2e1SPrashanth Swaminathan    all further uses in this file will refer to the 80-bit type.  */
41*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
42*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != 4
43*1fd5a2e1SPrashanth Swaminathan #  error FFI_TYPE_LONGDOUBLE out of date
44*1fd5a2e1SPrashanth Swaminathan # endif
45*1fd5a2e1SPrashanth Swaminathan #else
46*1fd5a2e1SPrashanth Swaminathan # undef FFI_TYPE_LONGDOUBLE
47*1fd5a2e1SPrashanth Swaminathan # define FFI_TYPE_LONGDOUBLE 4
48*1fd5a2e1SPrashanth Swaminathan #endif
49*1fd5a2e1SPrashanth Swaminathan 
50*1fd5a2e1SPrashanth Swaminathan #if defined(__GNUC__) && !defined(__declspec)
51*1fd5a2e1SPrashanth Swaminathan # define __declspec(x)  __attribute__((x))
52*1fd5a2e1SPrashanth Swaminathan #endif
53*1fd5a2e1SPrashanth Swaminathan 
54*1fd5a2e1SPrashanth Swaminathan #if defined(_MSC_VER) && defined(_M_IX86)
55*1fd5a2e1SPrashanth Swaminathan /* Stack is not 16-byte aligned on Windows.  */
56*1fd5a2e1SPrashanth Swaminathan #define STACK_ALIGN(bytes) (bytes)
57*1fd5a2e1SPrashanth Swaminathan #else
58*1fd5a2e1SPrashanth Swaminathan #define STACK_ALIGN(bytes) FFI_ALIGN (bytes, 16)
59*1fd5a2e1SPrashanth Swaminathan #endif
60*1fd5a2e1SPrashanth Swaminathan 
61*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing.  */
62*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)63*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep(ffi_cif *cif)
64*1fd5a2e1SPrashanth Swaminathan {
65*1fd5a2e1SPrashanth Swaminathan   size_t bytes = 0;
66*1fd5a2e1SPrashanth Swaminathan   int i, n, flags, cabi = cif->abi;
67*1fd5a2e1SPrashanth Swaminathan 
68*1fd5a2e1SPrashanth Swaminathan   switch (cabi)
69*1fd5a2e1SPrashanth Swaminathan     {
70*1fd5a2e1SPrashanth Swaminathan     case FFI_SYSV:
71*1fd5a2e1SPrashanth Swaminathan     case FFI_STDCALL:
72*1fd5a2e1SPrashanth Swaminathan     case FFI_THISCALL:
73*1fd5a2e1SPrashanth Swaminathan     case FFI_FASTCALL:
74*1fd5a2e1SPrashanth Swaminathan     case FFI_MS_CDECL:
75*1fd5a2e1SPrashanth Swaminathan     case FFI_PASCAL:
76*1fd5a2e1SPrashanth Swaminathan     case FFI_REGISTER:
77*1fd5a2e1SPrashanth Swaminathan       break;
78*1fd5a2e1SPrashanth Swaminathan     default:
79*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_ABI;
80*1fd5a2e1SPrashanth Swaminathan     }
81*1fd5a2e1SPrashanth Swaminathan 
82*1fd5a2e1SPrashanth Swaminathan   switch (cif->rtype->type)
83*1fd5a2e1SPrashanth Swaminathan     {
84*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_VOID:
85*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_VOID;
86*1fd5a2e1SPrashanth Swaminathan       break;
87*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
88*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_FLOAT;
89*1fd5a2e1SPrashanth Swaminathan       break;
90*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
91*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_DOUBLE;
92*1fd5a2e1SPrashanth Swaminathan       break;
93*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
94*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_LDOUBLE;
95*1fd5a2e1SPrashanth Swaminathan       break;
96*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT8:
97*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_UINT8;
98*1fd5a2e1SPrashanth Swaminathan       break;
99*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT16:
100*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_UINT16;
101*1fd5a2e1SPrashanth Swaminathan       break;
102*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT8:
103*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_SINT8;
104*1fd5a2e1SPrashanth Swaminathan       break;
105*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT16:
106*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_SINT16;
107*1fd5a2e1SPrashanth Swaminathan       break;
108*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_INT:
109*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT32:
110*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT32:
111*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_POINTER:
112*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_INT32;
113*1fd5a2e1SPrashanth Swaminathan       break;
114*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
115*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
116*1fd5a2e1SPrashanth Swaminathan       flags = X86_RET_INT64;
117*1fd5a2e1SPrashanth Swaminathan       break;
118*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
119*1fd5a2e1SPrashanth Swaminathan #ifndef X86
120*1fd5a2e1SPrashanth Swaminathan       /* ??? This should be a different ABI rather than an ifdef.  */
121*1fd5a2e1SPrashanth Swaminathan       if (cif->rtype->size == 1)
122*1fd5a2e1SPrashanth Swaminathan 	flags = X86_RET_STRUCT_1B;
123*1fd5a2e1SPrashanth Swaminathan       else if (cif->rtype->size == 2)
124*1fd5a2e1SPrashanth Swaminathan 	flags = X86_RET_STRUCT_2B;
125*1fd5a2e1SPrashanth Swaminathan       else if (cif->rtype->size == 4)
126*1fd5a2e1SPrashanth Swaminathan 	flags = X86_RET_INT32;
127*1fd5a2e1SPrashanth Swaminathan       else if (cif->rtype->size == 8)
128*1fd5a2e1SPrashanth Swaminathan 	flags = X86_RET_INT64;
129*1fd5a2e1SPrashanth Swaminathan       else
130*1fd5a2e1SPrashanth Swaminathan #endif
131*1fd5a2e1SPrashanth Swaminathan 	{
132*1fd5a2e1SPrashanth Swaminathan 	do_struct:
133*1fd5a2e1SPrashanth Swaminathan 	  switch (cabi)
134*1fd5a2e1SPrashanth Swaminathan 	    {
135*1fd5a2e1SPrashanth Swaminathan 	    case FFI_THISCALL:
136*1fd5a2e1SPrashanth Swaminathan 	    case FFI_FASTCALL:
137*1fd5a2e1SPrashanth Swaminathan 	    case FFI_STDCALL:
138*1fd5a2e1SPrashanth Swaminathan 	    case FFI_MS_CDECL:
139*1fd5a2e1SPrashanth Swaminathan 	      flags = X86_RET_STRUCTARG;
140*1fd5a2e1SPrashanth Swaminathan 	      break;
141*1fd5a2e1SPrashanth Swaminathan 	    default:
142*1fd5a2e1SPrashanth Swaminathan 	      flags = X86_RET_STRUCTPOP;
143*1fd5a2e1SPrashanth Swaminathan 	      break;
144*1fd5a2e1SPrashanth Swaminathan 	    }
145*1fd5a2e1SPrashanth Swaminathan 	  /* Allocate space for return value pointer.  */
146*1fd5a2e1SPrashanth Swaminathan 	  bytes += FFI_ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
147*1fd5a2e1SPrashanth Swaminathan 	}
148*1fd5a2e1SPrashanth Swaminathan       break;
149*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_COMPLEX:
150*1fd5a2e1SPrashanth Swaminathan       switch (cif->rtype->elements[0]->type)
151*1fd5a2e1SPrashanth Swaminathan 	{
152*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
153*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
154*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
155*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
156*1fd5a2e1SPrashanth Swaminathan 	  goto do_struct;
157*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
158*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_INT:
159*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
160*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
161*1fd5a2e1SPrashanth Swaminathan 	  flags = X86_RET_INT64;
162*1fd5a2e1SPrashanth Swaminathan 	  break;
163*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
164*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
165*1fd5a2e1SPrashanth Swaminathan 	  flags = X86_RET_INT32;
166*1fd5a2e1SPrashanth Swaminathan 	  break;
167*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
168*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
169*1fd5a2e1SPrashanth Swaminathan 	  flags = X86_RET_STRUCT_2B;
170*1fd5a2e1SPrashanth Swaminathan 	  break;
171*1fd5a2e1SPrashanth Swaminathan 	default:
172*1fd5a2e1SPrashanth Swaminathan 	  return FFI_BAD_TYPEDEF;
173*1fd5a2e1SPrashanth Swaminathan 	}
174*1fd5a2e1SPrashanth Swaminathan       break;
175*1fd5a2e1SPrashanth Swaminathan     default:
176*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_TYPEDEF;
177*1fd5a2e1SPrashanth Swaminathan     }
178*1fd5a2e1SPrashanth Swaminathan   cif->flags = flags;
179*1fd5a2e1SPrashanth Swaminathan 
180*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
181*1fd5a2e1SPrashanth Swaminathan     {
182*1fd5a2e1SPrashanth Swaminathan       ffi_type *t = cif->arg_types[i];
183*1fd5a2e1SPrashanth Swaminathan 
184*1fd5a2e1SPrashanth Swaminathan       bytes = FFI_ALIGN (bytes, t->alignment);
185*1fd5a2e1SPrashanth Swaminathan       bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG);
186*1fd5a2e1SPrashanth Swaminathan     }
187*1fd5a2e1SPrashanth Swaminathan   cif->bytes = bytes;
188*1fd5a2e1SPrashanth Swaminathan 
189*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
190*1fd5a2e1SPrashanth Swaminathan }
191*1fd5a2e1SPrashanth Swaminathan 
192*1fd5a2e1SPrashanth Swaminathan static ffi_arg
extend_basic_type(void * arg,int type)193*1fd5a2e1SPrashanth Swaminathan extend_basic_type(void *arg, int type)
194*1fd5a2e1SPrashanth Swaminathan {
195*1fd5a2e1SPrashanth Swaminathan   switch (type)
196*1fd5a2e1SPrashanth Swaminathan     {
197*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT8:
198*1fd5a2e1SPrashanth Swaminathan       return *(SINT8 *)arg;
199*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT8:
200*1fd5a2e1SPrashanth Swaminathan       return *(UINT8 *)arg;
201*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT16:
202*1fd5a2e1SPrashanth Swaminathan       return *(SINT16 *)arg;
203*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT16:
204*1fd5a2e1SPrashanth Swaminathan       return *(UINT16 *)arg;
205*1fd5a2e1SPrashanth Swaminathan 
206*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT32:
207*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT32:
208*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_POINTER:
209*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
210*1fd5a2e1SPrashanth Swaminathan       return *(UINT32 *)arg;
211*1fd5a2e1SPrashanth Swaminathan 
212*1fd5a2e1SPrashanth Swaminathan     default:
213*1fd5a2e1SPrashanth Swaminathan       abort();
214*1fd5a2e1SPrashanth Swaminathan     }
215*1fd5a2e1SPrashanth Swaminathan }
216*1fd5a2e1SPrashanth Swaminathan 
217*1fd5a2e1SPrashanth Swaminathan struct call_frame
218*1fd5a2e1SPrashanth Swaminathan {
219*1fd5a2e1SPrashanth Swaminathan   void *ebp;		/* 0 */
220*1fd5a2e1SPrashanth Swaminathan   void *retaddr;	/* 4 */
221*1fd5a2e1SPrashanth Swaminathan   void (*fn)(void);	/* 8 */
222*1fd5a2e1SPrashanth Swaminathan   int flags;		/* 12 */
223*1fd5a2e1SPrashanth Swaminathan   void *rvalue;		/* 16 */
224*1fd5a2e1SPrashanth Swaminathan   unsigned regs[3];	/* 20-28 */
225*1fd5a2e1SPrashanth Swaminathan };
226*1fd5a2e1SPrashanth Swaminathan 
227*1fd5a2e1SPrashanth Swaminathan struct abi_params
228*1fd5a2e1SPrashanth Swaminathan {
229*1fd5a2e1SPrashanth Swaminathan   int dir;		/* parameter growth direction */
230*1fd5a2e1SPrashanth Swaminathan   int static_chain;	/* the static chain register used by gcc */
231*1fd5a2e1SPrashanth Swaminathan   int nregs;		/* number of register parameters */
232*1fd5a2e1SPrashanth Swaminathan   int regs[3];
233*1fd5a2e1SPrashanth Swaminathan };
234*1fd5a2e1SPrashanth Swaminathan 
235*1fd5a2e1SPrashanth Swaminathan static const struct abi_params abi_params[FFI_LAST_ABI] = {
236*1fd5a2e1SPrashanth Swaminathan   [FFI_SYSV] = { 1, R_ECX, 0 },
237*1fd5a2e1SPrashanth Swaminathan   [FFI_THISCALL] = { 1, R_EAX, 1, { R_ECX } },
238*1fd5a2e1SPrashanth Swaminathan   [FFI_FASTCALL] = { 1, R_EAX, 2, { R_ECX, R_EDX } },
239*1fd5a2e1SPrashanth Swaminathan   [FFI_STDCALL] = { 1, R_ECX, 0 },
240*1fd5a2e1SPrashanth Swaminathan   [FFI_PASCAL] = { -1, R_ECX, 0 },
241*1fd5a2e1SPrashanth Swaminathan   /* ??? No defined static chain; gcc does not support REGISTER.  */
242*1fd5a2e1SPrashanth Swaminathan   [FFI_REGISTER] = { -1, R_ECX, 3, { R_EAX, R_EDX, R_ECX } },
243*1fd5a2e1SPrashanth Swaminathan   [FFI_MS_CDECL] = { 1, R_ECX, 0 }
244*1fd5a2e1SPrashanth Swaminathan };
245*1fd5a2e1SPrashanth Swaminathan 
246*1fd5a2e1SPrashanth Swaminathan #ifdef HAVE_FASTCALL
247*1fd5a2e1SPrashanth Swaminathan   #ifdef _MSC_VER
248*1fd5a2e1SPrashanth Swaminathan     #define FFI_DECLARE_FASTCALL __fastcall
249*1fd5a2e1SPrashanth Swaminathan   #else
250*1fd5a2e1SPrashanth Swaminathan     #define FFI_DECLARE_FASTCALL __declspec(fastcall)
251*1fd5a2e1SPrashanth Swaminathan   #endif
252*1fd5a2e1SPrashanth Swaminathan #else
253*1fd5a2e1SPrashanth Swaminathan   #define FFI_DECLARE_FASTCALL
254*1fd5a2e1SPrashanth Swaminathan #endif
255*1fd5a2e1SPrashanth Swaminathan 
256*1fd5a2e1SPrashanth Swaminathan extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_HIDDEN;
257*1fd5a2e1SPrashanth Swaminathan 
258*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)259*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
260*1fd5a2e1SPrashanth Swaminathan 	      void **avalue, void *closure)
261*1fd5a2e1SPrashanth Swaminathan {
262*1fd5a2e1SPrashanth Swaminathan   size_t rsize, bytes;
263*1fd5a2e1SPrashanth Swaminathan   struct call_frame *frame;
264*1fd5a2e1SPrashanth Swaminathan   char *stack, *argp;
265*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types;
266*1fd5a2e1SPrashanth Swaminathan   int flags, cabi, i, n, dir, narg_reg;
267*1fd5a2e1SPrashanth Swaminathan   const struct abi_params *pabi;
268*1fd5a2e1SPrashanth Swaminathan 
269*1fd5a2e1SPrashanth Swaminathan   flags = cif->flags;
270*1fd5a2e1SPrashanth Swaminathan   cabi = cif->abi;
271*1fd5a2e1SPrashanth Swaminathan   pabi = &abi_params[cabi];
272*1fd5a2e1SPrashanth Swaminathan   dir = pabi->dir;
273*1fd5a2e1SPrashanth Swaminathan 
274*1fd5a2e1SPrashanth Swaminathan   rsize = 0;
275*1fd5a2e1SPrashanth Swaminathan   if (rvalue == NULL)
276*1fd5a2e1SPrashanth Swaminathan     {
277*1fd5a2e1SPrashanth Swaminathan       switch (flags)
278*1fd5a2e1SPrashanth Swaminathan 	{
279*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_FLOAT:
280*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_DOUBLE:
281*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_LDOUBLE:
282*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_STRUCTPOP:
283*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_STRUCTARG:
284*1fd5a2e1SPrashanth Swaminathan 	  /* The float cases need to pop the 387 stack.
285*1fd5a2e1SPrashanth Swaminathan 	     The struct cases need to pass a valid pointer to the callee.  */
286*1fd5a2e1SPrashanth Swaminathan 	  rsize = cif->rtype->size;
287*1fd5a2e1SPrashanth Swaminathan 	  break;
288*1fd5a2e1SPrashanth Swaminathan 	default:
289*1fd5a2e1SPrashanth Swaminathan 	  /* We can pretend that the callee returns nothing.  */
290*1fd5a2e1SPrashanth Swaminathan 	  flags = X86_RET_VOID;
291*1fd5a2e1SPrashanth Swaminathan 	  break;
292*1fd5a2e1SPrashanth Swaminathan 	}
293*1fd5a2e1SPrashanth Swaminathan     }
294*1fd5a2e1SPrashanth Swaminathan 
295*1fd5a2e1SPrashanth Swaminathan   bytes = STACK_ALIGN (cif->bytes);
296*1fd5a2e1SPrashanth Swaminathan   stack = alloca(bytes + sizeof(*frame) + rsize);
297*1fd5a2e1SPrashanth Swaminathan   argp = (dir < 0 ? stack + bytes : stack);
298*1fd5a2e1SPrashanth Swaminathan   frame = (struct call_frame *)(stack + bytes);
299*1fd5a2e1SPrashanth Swaminathan   if (rsize)
300*1fd5a2e1SPrashanth Swaminathan     rvalue = frame + 1;
301*1fd5a2e1SPrashanth Swaminathan 
302*1fd5a2e1SPrashanth Swaminathan   frame->fn = fn;
303*1fd5a2e1SPrashanth Swaminathan   frame->flags = flags;
304*1fd5a2e1SPrashanth Swaminathan   frame->rvalue = rvalue;
305*1fd5a2e1SPrashanth Swaminathan   frame->regs[pabi->static_chain] = (unsigned)closure;
306*1fd5a2e1SPrashanth Swaminathan 
307*1fd5a2e1SPrashanth Swaminathan   narg_reg = 0;
308*1fd5a2e1SPrashanth Swaminathan   switch (flags)
309*1fd5a2e1SPrashanth Swaminathan     {
310*1fd5a2e1SPrashanth Swaminathan     case X86_RET_STRUCTARG:
311*1fd5a2e1SPrashanth Swaminathan       /* The pointer is passed as the first argument.  */
312*1fd5a2e1SPrashanth Swaminathan       if (pabi->nregs > 0)
313*1fd5a2e1SPrashanth Swaminathan 	{
314*1fd5a2e1SPrashanth Swaminathan 	  frame->regs[pabi->regs[0]] = (unsigned)rvalue;
315*1fd5a2e1SPrashanth Swaminathan 	  narg_reg = 1;
316*1fd5a2e1SPrashanth Swaminathan 	  break;
317*1fd5a2e1SPrashanth Swaminathan 	}
318*1fd5a2e1SPrashanth Swaminathan       /* fallthru */
319*1fd5a2e1SPrashanth Swaminathan     case X86_RET_STRUCTPOP:
320*1fd5a2e1SPrashanth Swaminathan       *(void **)argp = rvalue;
321*1fd5a2e1SPrashanth Swaminathan       argp += sizeof(void *);
322*1fd5a2e1SPrashanth Swaminathan       break;
323*1fd5a2e1SPrashanth Swaminathan     }
324*1fd5a2e1SPrashanth Swaminathan 
325*1fd5a2e1SPrashanth Swaminathan   arg_types = cif->arg_types;
326*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
327*1fd5a2e1SPrashanth Swaminathan     {
328*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
329*1fd5a2e1SPrashanth Swaminathan       void *valp = avalue[i];
330*1fd5a2e1SPrashanth Swaminathan       size_t z = ty->size;
331*1fd5a2e1SPrashanth Swaminathan       int t = ty->type;
332*1fd5a2e1SPrashanth Swaminathan 
333*1fd5a2e1SPrashanth Swaminathan       if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
334*1fd5a2e1SPrashanth Swaminathan         {
335*1fd5a2e1SPrashanth Swaminathan 	  ffi_arg val = extend_basic_type (valp, t);
336*1fd5a2e1SPrashanth Swaminathan 
337*1fd5a2e1SPrashanth Swaminathan 	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
338*1fd5a2e1SPrashanth Swaminathan 	    frame->regs[pabi->regs[narg_reg++]] = val;
339*1fd5a2e1SPrashanth Swaminathan 	  else if (dir < 0)
340*1fd5a2e1SPrashanth Swaminathan 	    {
341*1fd5a2e1SPrashanth Swaminathan 	      argp -= 4;
342*1fd5a2e1SPrashanth Swaminathan 	      *(ffi_arg *)argp = val;
343*1fd5a2e1SPrashanth Swaminathan 	    }
344*1fd5a2e1SPrashanth Swaminathan 	  else
345*1fd5a2e1SPrashanth Swaminathan 	    {
346*1fd5a2e1SPrashanth Swaminathan 	      *(ffi_arg *)argp = val;
347*1fd5a2e1SPrashanth Swaminathan 	      argp += 4;
348*1fd5a2e1SPrashanth Swaminathan 	    }
349*1fd5a2e1SPrashanth Swaminathan 	}
350*1fd5a2e1SPrashanth Swaminathan       else
351*1fd5a2e1SPrashanth Swaminathan 	{
352*1fd5a2e1SPrashanth Swaminathan 	  size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
353*1fd5a2e1SPrashanth Swaminathan 	  size_t align = FFI_SIZEOF_ARG;
354*1fd5a2e1SPrashanth Swaminathan 
355*1fd5a2e1SPrashanth Swaminathan 	  /* Issue 434: For thiscall and fastcall, if the paramter passed
356*1fd5a2e1SPrashanth Swaminathan 	     as 64-bit integer or struct, all following integer paramters
357*1fd5a2e1SPrashanth Swaminathan 	     will be passed on stack.  */
358*1fd5a2e1SPrashanth Swaminathan 	  if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
359*1fd5a2e1SPrashanth Swaminathan 	      && (t == FFI_TYPE_SINT64
360*1fd5a2e1SPrashanth Swaminathan 		  || t == FFI_TYPE_UINT64
361*1fd5a2e1SPrashanth Swaminathan 		  || t == FFI_TYPE_STRUCT))
362*1fd5a2e1SPrashanth Swaminathan 	    narg_reg = 2;
363*1fd5a2e1SPrashanth Swaminathan 
364*1fd5a2e1SPrashanth Swaminathan 	  /* Alignment rules for arguments are quite complex.  Vectors and
365*1fd5a2e1SPrashanth Swaminathan 	     structures with 16 byte alignment get it.  Note that long double
366*1fd5a2e1SPrashanth Swaminathan 	     on Darwin does have 16 byte alignment, and does not get this
367*1fd5a2e1SPrashanth Swaminathan 	     alignment if passed directly; a structure with a long double
368*1fd5a2e1SPrashanth Swaminathan 	     inside, however, would get 16 byte alignment.  Since libffi does
369*1fd5a2e1SPrashanth Swaminathan 	     not support vectors, we need non concern ourselves with other
370*1fd5a2e1SPrashanth Swaminathan 	     cases.  */
371*1fd5a2e1SPrashanth Swaminathan 	  if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
372*1fd5a2e1SPrashanth Swaminathan 	    align = 16;
373*1fd5a2e1SPrashanth Swaminathan 
374*1fd5a2e1SPrashanth Swaminathan 	  if (dir < 0)
375*1fd5a2e1SPrashanth Swaminathan 	    {
376*1fd5a2e1SPrashanth Swaminathan 	      /* ??? These reverse argument ABIs are probably too old
377*1fd5a2e1SPrashanth Swaminathan 		 to have cared about alignment.  Someone should check.  */
378*1fd5a2e1SPrashanth Swaminathan 	      argp -= za;
379*1fd5a2e1SPrashanth Swaminathan 	      memcpy (argp, valp, z);
380*1fd5a2e1SPrashanth Swaminathan 	    }
381*1fd5a2e1SPrashanth Swaminathan 	  else
382*1fd5a2e1SPrashanth Swaminathan 	    {
383*1fd5a2e1SPrashanth Swaminathan 	      argp = (char *)FFI_ALIGN (argp, align);
384*1fd5a2e1SPrashanth Swaminathan 	      memcpy (argp, valp, z);
385*1fd5a2e1SPrashanth Swaminathan 	      argp += za;
386*1fd5a2e1SPrashanth Swaminathan 	    }
387*1fd5a2e1SPrashanth Swaminathan 	}
388*1fd5a2e1SPrashanth Swaminathan     }
389*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (dir > 0 || argp == stack);
390*1fd5a2e1SPrashanth Swaminathan 
391*1fd5a2e1SPrashanth Swaminathan   ffi_call_i386 (frame, stack);
392*1fd5a2e1SPrashanth Swaminathan }
393*1fd5a2e1SPrashanth Swaminathan 
394*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)395*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
396*1fd5a2e1SPrashanth Swaminathan {
397*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, NULL);
398*1fd5a2e1SPrashanth Swaminathan }
399*1fd5a2e1SPrashanth Swaminathan 
400*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)401*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
402*1fd5a2e1SPrashanth Swaminathan 	     void **avalue, void *closure)
403*1fd5a2e1SPrashanth Swaminathan {
404*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, closure);
405*1fd5a2e1SPrashanth Swaminathan }
406*1fd5a2e1SPrashanth Swaminathan 
407*1fd5a2e1SPrashanth Swaminathan /** private members **/
408*1fd5a2e1SPrashanth Swaminathan 
409*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_closure_i386(void);
410*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_closure_STDCALL(void);
411*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_closure_REGISTER(void);
412*1fd5a2e1SPrashanth Swaminathan 
413*1fd5a2e1SPrashanth Swaminathan struct closure_frame
414*1fd5a2e1SPrashanth Swaminathan {
415*1fd5a2e1SPrashanth Swaminathan   unsigned rettemp[4];				/* 0 */
416*1fd5a2e1SPrashanth Swaminathan   unsigned regs[3];				/* 16-24 */
417*1fd5a2e1SPrashanth Swaminathan   ffi_cif *cif;					/* 28 */
418*1fd5a2e1SPrashanth Swaminathan   void (*fun)(ffi_cif*,void*,void**,void*);	/* 32 */
419*1fd5a2e1SPrashanth Swaminathan   void *user_data;				/* 36 */
420*1fd5a2e1SPrashanth Swaminathan };
421*1fd5a2e1SPrashanth Swaminathan 
422*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN FFI_DECLARE_FASTCALL
ffi_closure_inner(struct closure_frame * frame,char * stack)423*1fd5a2e1SPrashanth Swaminathan ffi_closure_inner (struct closure_frame *frame, char *stack)
424*1fd5a2e1SPrashanth Swaminathan {
425*1fd5a2e1SPrashanth Swaminathan   ffi_cif *cif = frame->cif;
426*1fd5a2e1SPrashanth Swaminathan   int cabi, i, n, flags, dir, narg_reg;
427*1fd5a2e1SPrashanth Swaminathan   const struct abi_params *pabi;
428*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types;
429*1fd5a2e1SPrashanth Swaminathan   char *argp;
430*1fd5a2e1SPrashanth Swaminathan   void *rvalue;
431*1fd5a2e1SPrashanth Swaminathan   void **avalue;
432*1fd5a2e1SPrashanth Swaminathan 
433*1fd5a2e1SPrashanth Swaminathan   cabi = cif->abi;
434*1fd5a2e1SPrashanth Swaminathan   flags = cif->flags;
435*1fd5a2e1SPrashanth Swaminathan   narg_reg = 0;
436*1fd5a2e1SPrashanth Swaminathan   rvalue = frame->rettemp;
437*1fd5a2e1SPrashanth Swaminathan   pabi = &abi_params[cabi];
438*1fd5a2e1SPrashanth Swaminathan   dir = pabi->dir;
439*1fd5a2e1SPrashanth Swaminathan   argp = (dir < 0 ? stack + STACK_ALIGN (cif->bytes) : stack);
440*1fd5a2e1SPrashanth Swaminathan 
441*1fd5a2e1SPrashanth Swaminathan   switch (flags)
442*1fd5a2e1SPrashanth Swaminathan     {
443*1fd5a2e1SPrashanth Swaminathan     case X86_RET_STRUCTARG:
444*1fd5a2e1SPrashanth Swaminathan       if (pabi->nregs > 0)
445*1fd5a2e1SPrashanth Swaminathan 	{
446*1fd5a2e1SPrashanth Swaminathan 	  rvalue = (void *)frame->regs[pabi->regs[0]];
447*1fd5a2e1SPrashanth Swaminathan 	  narg_reg = 1;
448*1fd5a2e1SPrashanth Swaminathan 	  frame->rettemp[0] = (unsigned)rvalue;
449*1fd5a2e1SPrashanth Swaminathan 	  break;
450*1fd5a2e1SPrashanth Swaminathan 	}
451*1fd5a2e1SPrashanth Swaminathan       /* fallthru */
452*1fd5a2e1SPrashanth Swaminathan     case X86_RET_STRUCTPOP:
453*1fd5a2e1SPrashanth Swaminathan       rvalue = *(void **)argp;
454*1fd5a2e1SPrashanth Swaminathan       argp += sizeof(void *);
455*1fd5a2e1SPrashanth Swaminathan       frame->rettemp[0] = (unsigned)rvalue;
456*1fd5a2e1SPrashanth Swaminathan       break;
457*1fd5a2e1SPrashanth Swaminathan     }
458*1fd5a2e1SPrashanth Swaminathan 
459*1fd5a2e1SPrashanth Swaminathan   n = cif->nargs;
460*1fd5a2e1SPrashanth Swaminathan   avalue = alloca(sizeof(void *) * n);
461*1fd5a2e1SPrashanth Swaminathan 
462*1fd5a2e1SPrashanth Swaminathan   arg_types = cif->arg_types;
463*1fd5a2e1SPrashanth Swaminathan   for (i = 0; i < n; ++i)
464*1fd5a2e1SPrashanth Swaminathan     {
465*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
466*1fd5a2e1SPrashanth Swaminathan       size_t z = ty->size;
467*1fd5a2e1SPrashanth Swaminathan       int t = ty->type;
468*1fd5a2e1SPrashanth Swaminathan       void *valp;
469*1fd5a2e1SPrashanth Swaminathan 
470*1fd5a2e1SPrashanth Swaminathan       if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
471*1fd5a2e1SPrashanth Swaminathan 	{
472*1fd5a2e1SPrashanth Swaminathan 	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
473*1fd5a2e1SPrashanth Swaminathan 	    valp = &frame->regs[pabi->regs[narg_reg++]];
474*1fd5a2e1SPrashanth Swaminathan 	  else if (dir < 0)
475*1fd5a2e1SPrashanth Swaminathan 	    {
476*1fd5a2e1SPrashanth Swaminathan 	      argp -= 4;
477*1fd5a2e1SPrashanth Swaminathan 	      valp = argp;
478*1fd5a2e1SPrashanth Swaminathan 	    }
479*1fd5a2e1SPrashanth Swaminathan 	  else
480*1fd5a2e1SPrashanth Swaminathan 	    {
481*1fd5a2e1SPrashanth Swaminathan 	      valp = argp;
482*1fd5a2e1SPrashanth Swaminathan 	      argp += 4;
483*1fd5a2e1SPrashanth Swaminathan 	    }
484*1fd5a2e1SPrashanth Swaminathan 	}
485*1fd5a2e1SPrashanth Swaminathan       else
486*1fd5a2e1SPrashanth Swaminathan 	{
487*1fd5a2e1SPrashanth Swaminathan 	  size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
488*1fd5a2e1SPrashanth Swaminathan 	  size_t align = FFI_SIZEOF_ARG;
489*1fd5a2e1SPrashanth Swaminathan 
490*1fd5a2e1SPrashanth Swaminathan 	  /* See the comment in ffi_call_int.  */
491*1fd5a2e1SPrashanth Swaminathan 	  if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
492*1fd5a2e1SPrashanth Swaminathan 	    align = 16;
493*1fd5a2e1SPrashanth Swaminathan 
494*1fd5a2e1SPrashanth Swaminathan 	  /* Issue 434: For thiscall and fastcall, if the paramter passed
495*1fd5a2e1SPrashanth Swaminathan 	     as 64-bit integer or struct, all following integer paramters
496*1fd5a2e1SPrashanth Swaminathan 	     will be passed on stack.  */
497*1fd5a2e1SPrashanth Swaminathan 	  if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
498*1fd5a2e1SPrashanth Swaminathan 	      && (t == FFI_TYPE_SINT64
499*1fd5a2e1SPrashanth Swaminathan 		  || t == FFI_TYPE_UINT64
500*1fd5a2e1SPrashanth Swaminathan 		  || t == FFI_TYPE_STRUCT))
501*1fd5a2e1SPrashanth Swaminathan 	    narg_reg = 2;
502*1fd5a2e1SPrashanth Swaminathan 
503*1fd5a2e1SPrashanth Swaminathan 	  if (dir < 0)
504*1fd5a2e1SPrashanth Swaminathan 	    {
505*1fd5a2e1SPrashanth Swaminathan 	      /* ??? These reverse argument ABIs are probably too old
506*1fd5a2e1SPrashanth Swaminathan 		 to have cared about alignment.  Someone should check.  */
507*1fd5a2e1SPrashanth Swaminathan 	      argp -= za;
508*1fd5a2e1SPrashanth Swaminathan 	      valp = argp;
509*1fd5a2e1SPrashanth Swaminathan 	    }
510*1fd5a2e1SPrashanth Swaminathan 	  else
511*1fd5a2e1SPrashanth Swaminathan 	    {
512*1fd5a2e1SPrashanth Swaminathan 	      argp = (char *)FFI_ALIGN (argp, align);
513*1fd5a2e1SPrashanth Swaminathan 	      valp = argp;
514*1fd5a2e1SPrashanth Swaminathan 	      argp += za;
515*1fd5a2e1SPrashanth Swaminathan 	    }
516*1fd5a2e1SPrashanth Swaminathan 	}
517*1fd5a2e1SPrashanth Swaminathan 
518*1fd5a2e1SPrashanth Swaminathan       avalue[i] = valp;
519*1fd5a2e1SPrashanth Swaminathan     }
520*1fd5a2e1SPrashanth Swaminathan 
521*1fd5a2e1SPrashanth Swaminathan   frame->fun (cif, rvalue, avalue, frame->user_data);
522*1fd5a2e1SPrashanth Swaminathan 
523*1fd5a2e1SPrashanth Swaminathan   if (cabi == FFI_STDCALL)
524*1fd5a2e1SPrashanth Swaminathan     return flags + (cif->bytes << X86_RET_POP_SHIFT);
525*1fd5a2e1SPrashanth Swaminathan   else
526*1fd5a2e1SPrashanth Swaminathan     return flags;
527*1fd5a2e1SPrashanth Swaminathan }
528*1fd5a2e1SPrashanth Swaminathan 
529*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)530*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure* closure,
531*1fd5a2e1SPrashanth Swaminathan                       ffi_cif* cif,
532*1fd5a2e1SPrashanth Swaminathan                       void (*fun)(ffi_cif*,void*,void**,void*),
533*1fd5a2e1SPrashanth Swaminathan                       void *user_data,
534*1fd5a2e1SPrashanth Swaminathan                       void *codeloc)
535*1fd5a2e1SPrashanth Swaminathan {
536*1fd5a2e1SPrashanth Swaminathan   char *tramp = closure->tramp;
537*1fd5a2e1SPrashanth Swaminathan   void (*dest)(void);
538*1fd5a2e1SPrashanth Swaminathan   int op = 0xb8;  /* movl imm, %eax */
539*1fd5a2e1SPrashanth Swaminathan 
540*1fd5a2e1SPrashanth Swaminathan   switch (cif->abi)
541*1fd5a2e1SPrashanth Swaminathan     {
542*1fd5a2e1SPrashanth Swaminathan     case FFI_SYSV:
543*1fd5a2e1SPrashanth Swaminathan     case FFI_THISCALL:
544*1fd5a2e1SPrashanth Swaminathan     case FFI_FASTCALL:
545*1fd5a2e1SPrashanth Swaminathan     case FFI_MS_CDECL:
546*1fd5a2e1SPrashanth Swaminathan       dest = ffi_closure_i386;
547*1fd5a2e1SPrashanth Swaminathan       break;
548*1fd5a2e1SPrashanth Swaminathan     case FFI_STDCALL:
549*1fd5a2e1SPrashanth Swaminathan     case FFI_PASCAL:
550*1fd5a2e1SPrashanth Swaminathan       dest = ffi_closure_STDCALL;
551*1fd5a2e1SPrashanth Swaminathan       break;
552*1fd5a2e1SPrashanth Swaminathan     case FFI_REGISTER:
553*1fd5a2e1SPrashanth Swaminathan       dest = ffi_closure_REGISTER;
554*1fd5a2e1SPrashanth Swaminathan       op = 0x68;  /* pushl imm */
555*1fd5a2e1SPrashanth Swaminathan       break;
556*1fd5a2e1SPrashanth Swaminathan     default:
557*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_ABI;
558*1fd5a2e1SPrashanth Swaminathan     }
559*1fd5a2e1SPrashanth Swaminathan 
560*1fd5a2e1SPrashanth Swaminathan   /* movl or pushl immediate.  */
561*1fd5a2e1SPrashanth Swaminathan   tramp[0] = op;
562*1fd5a2e1SPrashanth Swaminathan   *(void **)(tramp + 1) = codeloc;
563*1fd5a2e1SPrashanth Swaminathan 
564*1fd5a2e1SPrashanth Swaminathan   /* jmp dest */
565*1fd5a2e1SPrashanth Swaminathan   tramp[5] = 0xe9;
566*1fd5a2e1SPrashanth Swaminathan   *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
567*1fd5a2e1SPrashanth Swaminathan 
568*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
569*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
570*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
571*1fd5a2e1SPrashanth Swaminathan 
572*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
573*1fd5a2e1SPrashanth Swaminathan }
574*1fd5a2e1SPrashanth Swaminathan 
575*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_go_closure_EAX(void);
576*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_go_closure_ECX(void);
577*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_go_closure_STDCALL(void);
578*1fd5a2e1SPrashanth Swaminathan 
579*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))580*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
581*1fd5a2e1SPrashanth Swaminathan 		     void (*fun)(ffi_cif*,void*,void**,void*))
582*1fd5a2e1SPrashanth Swaminathan {
583*1fd5a2e1SPrashanth Swaminathan   void (*dest)(void);
584*1fd5a2e1SPrashanth Swaminathan 
585*1fd5a2e1SPrashanth Swaminathan   switch (cif->abi)
586*1fd5a2e1SPrashanth Swaminathan     {
587*1fd5a2e1SPrashanth Swaminathan     case FFI_SYSV:
588*1fd5a2e1SPrashanth Swaminathan     case FFI_MS_CDECL:
589*1fd5a2e1SPrashanth Swaminathan       dest = ffi_go_closure_ECX;
590*1fd5a2e1SPrashanth Swaminathan       break;
591*1fd5a2e1SPrashanth Swaminathan     case FFI_THISCALL:
592*1fd5a2e1SPrashanth Swaminathan     case FFI_FASTCALL:
593*1fd5a2e1SPrashanth Swaminathan       dest = ffi_go_closure_EAX;
594*1fd5a2e1SPrashanth Swaminathan       break;
595*1fd5a2e1SPrashanth Swaminathan     case FFI_STDCALL:
596*1fd5a2e1SPrashanth Swaminathan     case FFI_PASCAL:
597*1fd5a2e1SPrashanth Swaminathan       dest = ffi_go_closure_STDCALL;
598*1fd5a2e1SPrashanth Swaminathan       break;
599*1fd5a2e1SPrashanth Swaminathan     case FFI_REGISTER:
600*1fd5a2e1SPrashanth Swaminathan     default:
601*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_ABI;
602*1fd5a2e1SPrashanth Swaminathan     }
603*1fd5a2e1SPrashanth Swaminathan 
604*1fd5a2e1SPrashanth Swaminathan   closure->tramp = dest;
605*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
606*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
607*1fd5a2e1SPrashanth Swaminathan 
608*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
609*1fd5a2e1SPrashanth Swaminathan }
610*1fd5a2e1SPrashanth Swaminathan 
611*1fd5a2e1SPrashanth Swaminathan /* ------- Native raw API support -------------------------------- */
612*1fd5a2e1SPrashanth Swaminathan 
613*1fd5a2e1SPrashanth Swaminathan #if !FFI_NO_RAW_API
614*1fd5a2e1SPrashanth Swaminathan 
615*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_closure_raw_SYSV(void);
616*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN ffi_closure_raw_THISCALL(void);
617*1fd5a2e1SPrashanth Swaminathan 
618*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_raw_closure_loc(ffi_raw_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,ffi_raw *,void *),void * user_data,void * codeloc)619*1fd5a2e1SPrashanth Swaminathan ffi_prep_raw_closure_loc (ffi_raw_closure *closure,
620*1fd5a2e1SPrashanth Swaminathan                           ffi_cif *cif,
621*1fd5a2e1SPrashanth Swaminathan                           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
622*1fd5a2e1SPrashanth Swaminathan                           void *user_data,
623*1fd5a2e1SPrashanth Swaminathan                           void *codeloc)
624*1fd5a2e1SPrashanth Swaminathan {
625*1fd5a2e1SPrashanth Swaminathan   char *tramp = closure->tramp;
626*1fd5a2e1SPrashanth Swaminathan   void (*dest)(void);
627*1fd5a2e1SPrashanth Swaminathan   int i;
628*1fd5a2e1SPrashanth Swaminathan 
629*1fd5a2e1SPrashanth Swaminathan   /* We currently don't support certain kinds of arguments for raw
630*1fd5a2e1SPrashanth Swaminathan      closures.  This should be implemented by a separate assembly
631*1fd5a2e1SPrashanth Swaminathan      language routine, since it would require argument processing,
632*1fd5a2e1SPrashanth Swaminathan      something we don't do now for performance.  */
633*1fd5a2e1SPrashanth Swaminathan   for (i = cif->nargs-1; i >= 0; i--)
634*1fd5a2e1SPrashanth Swaminathan     switch (cif->arg_types[i]->type)
635*1fd5a2e1SPrashanth Swaminathan       {
636*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_STRUCT:
637*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_LONGDOUBLE:
638*1fd5a2e1SPrashanth Swaminathan 	return FFI_BAD_TYPEDEF;
639*1fd5a2e1SPrashanth Swaminathan       }
640*1fd5a2e1SPrashanth Swaminathan 
641*1fd5a2e1SPrashanth Swaminathan   switch (cif->abi)
642*1fd5a2e1SPrashanth Swaminathan     {
643*1fd5a2e1SPrashanth Swaminathan     case FFI_THISCALL:
644*1fd5a2e1SPrashanth Swaminathan       dest = ffi_closure_raw_THISCALL;
645*1fd5a2e1SPrashanth Swaminathan       break;
646*1fd5a2e1SPrashanth Swaminathan     case FFI_SYSV:
647*1fd5a2e1SPrashanth Swaminathan       dest = ffi_closure_raw_SYSV;
648*1fd5a2e1SPrashanth Swaminathan       break;
649*1fd5a2e1SPrashanth Swaminathan     default:
650*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_ABI;
651*1fd5a2e1SPrashanth Swaminathan     }
652*1fd5a2e1SPrashanth Swaminathan 
653*1fd5a2e1SPrashanth Swaminathan   /* movl imm, %eax.  */
654*1fd5a2e1SPrashanth Swaminathan   tramp[0] = 0xb8;
655*1fd5a2e1SPrashanth Swaminathan   *(void **)(tramp + 1) = codeloc;
656*1fd5a2e1SPrashanth Swaminathan 
657*1fd5a2e1SPrashanth Swaminathan   /* jmp dest */
658*1fd5a2e1SPrashanth Swaminathan   tramp[5] = 0xe9;
659*1fd5a2e1SPrashanth Swaminathan   *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
660*1fd5a2e1SPrashanth Swaminathan 
661*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
662*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
663*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
664*1fd5a2e1SPrashanth Swaminathan 
665*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
666*1fd5a2e1SPrashanth Swaminathan }
667*1fd5a2e1SPrashanth Swaminathan 
668*1fd5a2e1SPrashanth Swaminathan void
ffi_raw_call(ffi_cif * cif,void (* fn)(void),void * rvalue,ffi_raw * avalue)669*1fd5a2e1SPrashanth Swaminathan ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
670*1fd5a2e1SPrashanth Swaminathan {
671*1fd5a2e1SPrashanth Swaminathan   size_t rsize, bytes;
672*1fd5a2e1SPrashanth Swaminathan   struct call_frame *frame;
673*1fd5a2e1SPrashanth Swaminathan   char *stack, *argp;
674*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types;
675*1fd5a2e1SPrashanth Swaminathan   int flags, cabi, i, n, narg_reg;
676*1fd5a2e1SPrashanth Swaminathan   const struct abi_params *pabi;
677*1fd5a2e1SPrashanth Swaminathan 
678*1fd5a2e1SPrashanth Swaminathan   flags = cif->flags;
679*1fd5a2e1SPrashanth Swaminathan   cabi = cif->abi;
680*1fd5a2e1SPrashanth Swaminathan   pabi = &abi_params[cabi];
681*1fd5a2e1SPrashanth Swaminathan 
682*1fd5a2e1SPrashanth Swaminathan   rsize = 0;
683*1fd5a2e1SPrashanth Swaminathan   if (rvalue == NULL)
684*1fd5a2e1SPrashanth Swaminathan     {
685*1fd5a2e1SPrashanth Swaminathan       switch (flags)
686*1fd5a2e1SPrashanth Swaminathan 	{
687*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_FLOAT:
688*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_DOUBLE:
689*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_LDOUBLE:
690*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_STRUCTPOP:
691*1fd5a2e1SPrashanth Swaminathan 	case X86_RET_STRUCTARG:
692*1fd5a2e1SPrashanth Swaminathan 	  /* The float cases need to pop the 387 stack.
693*1fd5a2e1SPrashanth Swaminathan 	     The struct cases need to pass a valid pointer to the callee.  */
694*1fd5a2e1SPrashanth Swaminathan 	  rsize = cif->rtype->size;
695*1fd5a2e1SPrashanth Swaminathan 	  break;
696*1fd5a2e1SPrashanth Swaminathan 	default:
697*1fd5a2e1SPrashanth Swaminathan 	  /* We can pretend that the callee returns nothing.  */
698*1fd5a2e1SPrashanth Swaminathan 	  flags = X86_RET_VOID;
699*1fd5a2e1SPrashanth Swaminathan 	  break;
700*1fd5a2e1SPrashanth Swaminathan 	}
701*1fd5a2e1SPrashanth Swaminathan     }
702*1fd5a2e1SPrashanth Swaminathan 
703*1fd5a2e1SPrashanth Swaminathan   bytes = STACK_ALIGN (cif->bytes);
704*1fd5a2e1SPrashanth Swaminathan   argp = stack =
705*1fd5a2e1SPrashanth Swaminathan       (void *)((uintptr_t)alloca(bytes + sizeof(*frame) + rsize + 15) & ~16);
706*1fd5a2e1SPrashanth Swaminathan   frame = (struct call_frame *)(stack + bytes);
707*1fd5a2e1SPrashanth Swaminathan   if (rsize)
708*1fd5a2e1SPrashanth Swaminathan     rvalue = frame + 1;
709*1fd5a2e1SPrashanth Swaminathan 
710*1fd5a2e1SPrashanth Swaminathan   frame->fn = fn;
711*1fd5a2e1SPrashanth Swaminathan   frame->flags = flags;
712*1fd5a2e1SPrashanth Swaminathan   frame->rvalue = rvalue;
713*1fd5a2e1SPrashanth Swaminathan 
714*1fd5a2e1SPrashanth Swaminathan   narg_reg = 0;
715*1fd5a2e1SPrashanth Swaminathan   switch (flags)
716*1fd5a2e1SPrashanth Swaminathan     {
717*1fd5a2e1SPrashanth Swaminathan     case X86_RET_STRUCTARG:
718*1fd5a2e1SPrashanth Swaminathan       /* The pointer is passed as the first argument.  */
719*1fd5a2e1SPrashanth Swaminathan       if (pabi->nregs > 0)
720*1fd5a2e1SPrashanth Swaminathan 	{
721*1fd5a2e1SPrashanth Swaminathan 	  frame->regs[pabi->regs[0]] = (unsigned)rvalue;
722*1fd5a2e1SPrashanth Swaminathan 	  narg_reg = 1;
723*1fd5a2e1SPrashanth Swaminathan 	  break;
724*1fd5a2e1SPrashanth Swaminathan 	}
725*1fd5a2e1SPrashanth Swaminathan       /* fallthru */
726*1fd5a2e1SPrashanth Swaminathan     case X86_RET_STRUCTPOP:
727*1fd5a2e1SPrashanth Swaminathan       *(void **)argp = rvalue;
728*1fd5a2e1SPrashanth Swaminathan       argp += sizeof(void *);
729*1fd5a2e1SPrashanth Swaminathan       bytes -= sizeof(void *);
730*1fd5a2e1SPrashanth Swaminathan       break;
731*1fd5a2e1SPrashanth Swaminathan     }
732*1fd5a2e1SPrashanth Swaminathan 
733*1fd5a2e1SPrashanth Swaminathan   arg_types = cif->arg_types;
734*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++)
735*1fd5a2e1SPrashanth Swaminathan     {
736*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
737*1fd5a2e1SPrashanth Swaminathan       size_t z = ty->size;
738*1fd5a2e1SPrashanth Swaminathan       int t = ty->type;
739*1fd5a2e1SPrashanth Swaminathan 
740*1fd5a2e1SPrashanth Swaminathan       if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT)
741*1fd5a2e1SPrashanth Swaminathan 	{
742*1fd5a2e1SPrashanth Swaminathan 	  ffi_arg val = extend_basic_type (avalue, t);
743*1fd5a2e1SPrashanth Swaminathan 	  frame->regs[pabi->regs[narg_reg++]] = val;
744*1fd5a2e1SPrashanth Swaminathan 	  z = FFI_SIZEOF_ARG;
745*1fd5a2e1SPrashanth Swaminathan 	}
746*1fd5a2e1SPrashanth Swaminathan       else
747*1fd5a2e1SPrashanth Swaminathan 	{
748*1fd5a2e1SPrashanth Swaminathan 	  memcpy (argp, avalue, z);
749*1fd5a2e1SPrashanth Swaminathan 	  z = FFI_ALIGN (z, FFI_SIZEOF_ARG);
750*1fd5a2e1SPrashanth Swaminathan 	  argp += z;
751*1fd5a2e1SPrashanth Swaminathan 	}
752*1fd5a2e1SPrashanth Swaminathan       avalue += z;
753*1fd5a2e1SPrashanth Swaminathan       bytes -= z;
754*1fd5a2e1SPrashanth Swaminathan     }
755*1fd5a2e1SPrashanth Swaminathan   if (i < n)
756*1fd5a2e1SPrashanth Swaminathan     memcpy (argp, avalue, bytes);
757*1fd5a2e1SPrashanth Swaminathan 
758*1fd5a2e1SPrashanth Swaminathan   ffi_call_i386 (frame, stack);
759*1fd5a2e1SPrashanth Swaminathan }
760*1fd5a2e1SPrashanth Swaminathan #endif /* !FFI_NO_RAW_API */
761*1fd5a2e1SPrashanth Swaminathan #endif /* __i386__ */
762