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