1
/* -----------------------------------------------------------------------
2
ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
3
Copyright (c) 2002 Ranjit Mathew
4
Copyright (c) 2002 Bo Thorsen
5
Copyright (c) 2002 Roger Sayle
7
x86 Foreign Function Interface
9
Permission is hereby granted, free of charge, to any person obtaining
10
a copy of this software and associated documentation files (the
11
``Software''), to deal in the Software without restriction, including
12
without limitation the rights to use, copy, modify, merge, publish,
13
distribute, sublicense, and/or sell copies of the Software, and to
14
permit persons to whom the Software is furnished to do so, subject to
15
the following conditions:
17
The above copyright notice and this permission notice shall be included
18
in all copies or substantial portions of the Software.
20
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26
OTHER DEALINGS IN THE SOFTWARE.
27
----------------------------------------------------------------------- */
30
#include <ffi_common.h>
34
/* ffi_prep_args is called by the assembly routine once stack space
35
has been allocated for the function's arguments */
37
extern void Py_FatalError(char *msg);
40
void ffi_prep_args(char *stack, extended_cif *ecif)
43
register unsigned int i;
44
register void **p_argv;
46
register ffi_type **p_arg;
49
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
51
*(void **) argp = ecif->rvalue;
52
argp += sizeof(void *);
55
p_argv = ecif->avalue;
57
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
63
/* Align if necessary */
64
if ((sizeof(void *) - 1) & (size_t) argp)
65
argp = (char *) ALIGN(argp, sizeof(void *));
71
switch ((*p_arg)->type)
74
*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
78
*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
82
*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
86
*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
90
*(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
94
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
98
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
107
memcpy(argp, *p_argv, z);
113
if (argp - stack > ecif->cif->bytes)
115
Py_FatalError("FFI BUG: not enough stack space for arguments");
120
/* Perform machine dependent cif processing */
121
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
123
/* Set the return type flag */
124
switch (cif->rtype->type)
127
case FFI_TYPE_STRUCT:
128
case FFI_TYPE_SINT64:
130
case FFI_TYPE_DOUBLE:
131
case FFI_TYPE_LONGDOUBLE:
132
cif->flags = (unsigned) cif->rtype->type;
135
case FFI_TYPE_UINT64:
137
case FFI_TYPE_POINTER:
139
cif->flags = FFI_TYPE_SINT64;
143
cif->flags = FFI_TYPE_INT;
154
ffi_call_SYSV(void (*)(char *, extended_cif *),
155
/*@out@*/ extended_cif *,
157
/*@out@*/ unsigned *,
165
ffi_call_STDCALL(void (*)(char *, extended_cif *),
166
/*@out@*/ extended_cif *,
168
/*@out@*/ unsigned *,
176
ffi_call_AMD64(void (*)(char *, extended_cif *),
177
/*@out@*/ extended_cif *,
179
/*@out@*/ unsigned *,
184
ffi_call(/*@dependent@*/ ffi_cif *cif,
186
/*@out@*/ void *rvalue,
187
/*@dependent@*/ void **avalue)
192
ecif.avalue = avalue;
194
/* If the return value is a struct and we don't have a return */
195
/* value address then we need to make one */
197
if ((rvalue == NULL) &&
198
(cif->rtype->type == FFI_TYPE_STRUCT))
201
ecif.rvalue = alloca(cif->rtype->size);
205
ecif.rvalue = rvalue;
213
return ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
214
cif->flags, ecif.rvalue, fn);
220
return ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
221
cif->flags, ecif.rvalue, fn);
227
/* Function call needs at least 40 bytes stack size, on win64 AMD64 */
228
return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,
229
cif->flags, ecif.rvalue, fn);
238
return -1; /* theller: Hrm. */
242
/** private members **/
244
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
245
void** args, ffi_cif* cif);
246
/* This function is jumped to by the trampoline */
251
static void __fastcall
253
ffi_closure_SYSV (ffi_closure *closure, int *argp)
255
// this is our return value storage
258
// our various things...
261
unsigned short rtype;
262
void *resp = (void*)&res;
263
void *args = &argp[1];
266
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
268
/* this call will initialize ARG_AREA, such that each
269
* element in that array points to the corresponding
270
* value on the stack; and if the function returns
271
* a structure, it will re-set RESP to point to the
272
* structure return address. */
274
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
276
(closure->fun) (cif, resp, arg_area, closure->user_data);
280
#if defined(_WIN32) && !defined(_WIN64)
282
/* now, do a generic return based on the value of rtype */
283
if (rtype == FFI_TYPE_INT)
286
_asm mov eax, [eax] ;
288
else if (rtype == FFI_TYPE_FLOAT)
291
_asm fld DWORD PTR [eax] ;
292
// asm ("flds (%0)" : : "r" (resp) : "st" );
294
else if (rtype == FFI_TYPE_DOUBLE)
297
_asm fld QWORD PTR [eax] ;
298
// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
300
else if (rtype == FFI_TYPE_LONGDOUBLE)
302
// asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
304
else if (rtype == FFI_TYPE_SINT64)
307
_asm mov eax, [edx] ;
308
_asm mov edx, [edx + 4] ;
309
// asm ("movl 0(%0),%%eax;"
310
// "movl 4(%0),%%edx"
315
/* now, do a generic return based on the value of rtype */
316
if (rtype == FFI_TYPE_INT)
318
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
320
else if (rtype == FFI_TYPE_FLOAT)
322
asm ("flds (%0)" : : "r" (resp) : "st" );
324
else if (rtype == FFI_TYPE_DOUBLE)
326
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
328
else if (rtype == FFI_TYPE_LONGDOUBLE)
330
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
332
else if (rtype == FFI_TYPE_SINT64)
334
asm ("movl 0(%0),%%eax;"
343
/* The result is returned in rax. This does the right thing for
344
result types except for floats; we have to 'mov xmm0, rax' in the
345
caller to correct this.
347
return *(void **)resp;
353
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
354
void **avalue, ffi_cif *cif)
357
register unsigned int i;
358
register void **p_argv;
360
register ffi_type **p_arg;
364
if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
365
*rvalue = *(void **) argp;
371
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
375
/* Align if necessary */
376
if ((sizeof(char *) - 1) & (size_t) argp) {
377
argp = (char *) ALIGN(argp, sizeof(char*));
382
/* because we're little endian, this is what it turns into. */
384
*p_argv = (void*) argp;
393
/* the cif must already be prep'ed */
394
extern void ffi_closure_OUTER();
397
ffi_prep_closure (ffi_closure* closure,
399
void (*fun)(ffi_cif*,void*,void**,void*),
407
FFI_ASSERT (cif->abi == FFI_SYSV);
409
if (cif->abi == FFI_SYSV)
412
else if (cif->abi == FFI_STDCALL)
418
tramp = &closure->tramp[0];
420
#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
421
#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
422
#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
423
#define INT(x) *(int*)tramp = x, tramp += sizeof(int)
426
if (cif->nargs >= 1 &&
427
(cif->arg_types[0]->type == FFI_TYPE_FLOAT
428
|| cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
430
if (cif->nargs >= 2 &&
431
(cif->arg_types[1]->type == FFI_TYPE_FLOAT
432
|| cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
434
if (cif->nargs >= 3 &&
435
(cif->arg_types[2]->type == FFI_TYPE_FLOAT
436
|| cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
438
if (cif->nargs >= 4 &&
439
(cif->arg_types[3]->type == FFI_TYPE_FLOAT
440
|| cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
443
/* 41 BB ---- mov r11d,mask */
444
BYTES("\x41\xBB"); INT(mask);
446
/* 48 B8 -------- mov rax, closure */
447
BYTES("\x48\xB8"); POINTER(closure);
449
/* 49 BA -------- mov r10, ffi_closure_OUTER */
450
BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
452
/* 41 FF E2 jmp r10 */
453
BYTES("\x41\xFF\xE2");
457
/* mov ecx, closure */
458
BYTES("\xb9"); POINTER(closure);
463
/* call ffi_closure_SYSV */
464
BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
472
if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
473
Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
476
closure->user_data = user_data;