2
/* -----------------------------------------------------------------------
3
ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
4
Copyright (c) 2002 Ranjit Mathew
5
Copyright (c) 2002 Bo Thorsen
6
Copyright (c) 2002 Roger Sayle
8
x86 Foreign Function Interface
10
Permission is hereby granted, free of charge, to any person obtaining
11
a copy of this software and associated documentation files (the
12
``Software''), to deal in the Software without restriction, including
13
without limitation the rights to use, copy, modify, merge, publish,
14
distribute, sublicense, and/or sell copies of the Software, and to
15
permit persons to whom the Software is furnished to do so, subject to
16
the following conditions:
18
The above copyright notice and this permission notice shall be included
19
in all copies or substantial portions of the Software.
21
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27
OTHER DEALINGS IN THE SOFTWARE.
28
----------------------------------------------------------------------- */
33
#include <ffi_common.h>
37
//void ffi_prep_args(char *stack, extended_cif *ecif);
43
if (tp->type == FFI_TYPE_STRUCT)
45
// int size = tp->size;
52
case 1: case 2: case 4: case 8:
62
/* ffi_prep_args is called by the assembly routine once stack space
63
has been allocated for the function's arguments */
65
extern void ffi_prep_args(char*, extended_cif*);
72
register unsigned int i;
73
register void** p_argv = ecif->avalue;
74
register char* argp = stack;
75
register ffi_type** p_arg;
77
if (retval_on_stack(ecif->cif->rtype))
79
*(void**)argp = ecif->rvalue;
83
p_arg = ecif->cif->arg_types;
85
for (i = ecif->cif->nargs; i > 0; i--, p_arg++, p_argv++)
87
size_t z = (*p_arg)->size;
89
/* Align if necessary */
90
if ((sizeof(int) - 1) & (unsigned)argp)
91
argp = (char*)ALIGN(argp, sizeof(int));
97
switch ((*p_arg)->type)
100
*(signed int*)argp = (signed int)*(SINT8*)(*p_argv);
104
*(unsigned int*)argp = (unsigned int)*(UINT8*)(*p_argv);
107
case FFI_TYPE_SINT16:
108
*(signed int*)argp = (signed int)*(SINT16*)(*p_argv);
111
case FFI_TYPE_UINT16:
112
*(unsigned int*)argp = (unsigned int)*(UINT16*)(*p_argv);
115
case FFI_TYPE_SINT32:
116
*(signed int*)argp = (signed int)*(SINT32*)(*p_argv);
119
case FFI_TYPE_UINT32:
120
*(unsigned int*)argp = (unsigned int)*(UINT32*)(*p_argv);
123
case FFI_TYPE_STRUCT:
124
*(unsigned int*)argp = (unsigned int)*(UINT32*)(*p_argv);
133
memcpy(argp, *p_argv, z);
139
/* Perform machine dependent cif processing */
141
ffi_prep_cif_machdep(
144
/* Set the return type flag */
145
switch (cif->rtype->type)
147
#if !defined(X86_WIN32) && !defined(X86_DARWIN)
148
case FFI_TYPE_STRUCT:
151
case FFI_TYPE_SINT64:
153
case FFI_TYPE_DOUBLE:
154
case FFI_TYPE_LONGDOUBLE:
155
cif->flags = (unsigned)cif->rtype->type;
158
case FFI_TYPE_UINT64:
159
cif->flags = FFI_TYPE_SINT64;
162
#if defined(X86_WIN32) || defined(X86_DARWIN)
163
case FFI_TYPE_STRUCT:
164
switch (cif->rtype->size)
167
cif->flags = FFI_TYPE_SINT8;
171
cif->flags = FFI_TYPE_SINT16;
175
cif->flags = FFI_TYPE_INT;
179
cif->flags = FFI_TYPE_SINT64;
183
cif->flags = FFI_TYPE_STRUCT;
191
cif->flags = FFI_TYPE_INT;
195
/* Darwin: The stack needs to be aligned to a multiple of 16 bytes */
196
cif->bytes = (cif->bytes + 15) & ~0xF;
205
void (*)(char *, extended_cif *),
206
/*@out@*/ extended_cif* ,
209
/*@out@*/ unsigned* ,
219
void (char *, extended_cif *),
220
/*@out@*/ extended_cif* ,
223
/*@out@*/ unsigned* ,
227
#endif /* X86_WIN32 */
231
/*@dependent@*/ ffi_cif* cif,
233
/*@out@*/ void* rvalue,
234
/*@dependent@*/ void** avalue)
239
ecif.avalue = avalue;
241
/* If the return value is a struct and we don't have a return
242
value address then we need to make one. */
244
if ((rvalue == NULL) && retval_on_stack(cif->rtype))
247
ecif.rvalue = alloca(cif->rtype->size);
251
ecif.rvalue = rvalue;
257
/* To avoid changing the assembly code make sure the size of the argument
258
block is a multiple of 16. Then add 8 to compensate for local variables
260
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
261
cif->flags, ecif.rvalue, fn);
268
ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
269
cif->flags, ecif.rvalue, fn);
272
#endif /* X86_WIN32 */
280
/** private members **/
284
ffi_closure* closure) __attribute__((regparm(1)));
288
ffi_closure_raw_SYSV(
289
ffi_raw_closure* closure) __attribute__((regparm(1)));
295
ffi_prep_incoming_args_SYSV(
302
register unsigned int i;
303
register void** p_argv = avalue;
304
register char* argp = stack;
305
register ffi_type** p_arg;
307
if (retval_on_stack(cif->rtype))
309
*rvalue = *(void**)argp;
313
for (i = cif->nargs, p_arg = cif->arg_types; i > 0; i--, p_arg++, p_argv++)
317
/* Align if necessary */
318
if ((sizeof(int) - 1) & (unsigned)argp)
319
argp = (char*)ALIGN(argp, sizeof(int));
321
// z = (*p_arg)->size;
323
/* because we're little endian, this is what it turns into. */
324
*p_argv = (void*)argp;
326
argp += (*p_arg)->size;
330
/* This function is jumped to by the trampoline */
331
__attribute__((regparm(1)))
334
ffi_closure* closure)
337
ffi_cif* cif = closure->cif;
338
void** arg_area = (void**)alloca(cif->nargs * sizeof(void*));
339
void* resp = (void*)&res;
340
void* args = __builtin_dwarf_cfa();
342
/* This call will initialize ARG_AREA, such that each
343
element in that array points to the corresponding
344
value on the stack; and if the function returns
345
a structure, it will reset RESP to point to the
346
structure return address. */
347
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
349
(closure->fun)(cif, resp, arg_area, closure->user_data);
351
/* now, do a generic return based on the value of rtype */
352
if (cif->flags == FFI_TYPE_INT)
353
asm("movl (%0),%%eax"
354
: : "r" (resp) : "eax");
355
else if (cif->flags == FFI_TYPE_FLOAT)
357
: : "r" (resp) : "st");
358
else if (cif->flags == FFI_TYPE_DOUBLE)
360
: : "r" (resp) : "st", "st(1)");
361
else if (cif->flags == FFI_TYPE_LONGDOUBLE)
363
: : "r" (resp) : "st", "st(1)");
364
else if (cif->flags == FFI_TYPE_SINT64)
365
asm("movl 0(%0),%%eax;"
370
#if defined(X86_WIN32) || defined(X86_DARWIN)
371
else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */
372
asm("movsbl (%0),%%eax"
373
: : "r" (resp) : "eax");
374
else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */
375
asm("movswl (%0),%%eax"
376
: : "r" (resp) : "eax");
379
else if (cif->flags == FFI_TYPE_STRUCT)
380
asm("lea -8(%ebp),%esp;"
388
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
389
#define FFI_INIT_TRAMPOLINE(TRAMP, FUN, CTX) \
391
unsigned char* __tramp = (unsigned char*)(TRAMP); \
392
unsigned int __fun = (unsigned int)(FUN); \
393
unsigned int __ctx = (unsigned int)(CTX); \
394
unsigned int __dis = __fun - ((unsigned int)__tramp + FFI_TRAMPOLINE_SIZE); \
395
*(unsigned char*)&__tramp[0] = 0xb8; \
396
*(unsigned int*)&__tramp[1] = __ctx; /* movl __ctx, %eax */ \
397
*(unsigned char*)&__tramp[5] = 0xe9; \
398
*(unsigned int*)&__tramp[6] = __dis; /* jmp __fun */ \
401
/* the cif must already be prep'ed */
404
ffi_closure* closure,
406
void (*fun)(ffi_cif*,void*,void**,void*),
409
// FFI_ASSERT(cif->abi == FFI_SYSV);
410
if (cif->abi != FFI_SYSV)
413
FFI_INIT_TRAMPOLINE(closure->tramp, &ffi_closure_SYSV, (void*)closure);
416
closure->user_data = user_data;
422
/* ------- Native raw API support -------------------------------- */
426
__attribute__((regparm(1)))
428
ffi_closure_raw_SYSV(
429
ffi_raw_closure* closure)
432
ffi_raw* raw_args = (ffi_raw*)__builtin_dwarf_cfa();
433
ffi_cif* cif = closure->cif;
434
unsigned short rtype = cif->flags;
435
void* resp = (void*)&res;
437
(closure->fun)(cif, resp, raw_args, closure->user_data);
439
/* now, do a generic return based on the value of rtype */
440
if (rtype == FFI_TYPE_INT)
441
asm("movl (%0),%%eax"
442
: : "r" (resp) : "eax");
443
else if (rtype == FFI_TYPE_FLOAT)
445
: : "r" (resp) : "st");
446
else if (rtype == FFI_TYPE_DOUBLE)
448
: : "r" (resp) : "st", "st(1)");
449
else if (rtype == FFI_TYPE_LONGDOUBLE)
451
: : "r" (resp) : "st", "st(1)");
452
else if (rtype == FFI_TYPE_SINT64)
453
asm("movl 0(%0),%%eax;"
455
: : "r" (resp) : "eax", "edx");
459
ffi_prep_raw_closure(
460
ffi_raw_closure* closure,
462
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
465
// FFI_ASSERT (cif->abi == FFI_SYSV);
466
if (cif->abi != FFI_SYSV)
471
/* We currently don't support certain kinds of arguments for raw
472
closures. This should be implemented by a separate assembly language
473
routine, since it would require argument processing, something we
474
don't do now for performance. */
475
for (i = cif->nargs - 1; i >= 0; i--)
477
FFI_ASSERT(cif->arg_types[i]->type != FFI_TYPE_STRUCT);
478
FFI_ASSERT(cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
481
FFI_INIT_TRAMPOLINE(closure->tramp, &ffi_closure_raw_SYSV, (void*)closure);
484
closure->user_data = user_data;
495
memcpy(stack, ecif->avalue, ecif->cif->bytes);
498
/* We borrow this routine from libffi (it must be changed, though, to
499
actually call the function passed in the first argument. as of
500
libffi-1.20, this is not the case.) */
503
// void (*)(char *, extended_cif *),
504
///*@out@*/ extended_cif* ,
507
//*@out@*/ unsigned* ,
513
void (*)(char *, extended_cif *),
514
/*@out@*/ extended_cif* ,
517
/*@out@*/ unsigned* ,
523
/*@dependent@*/ ffi_cif* cif,
525
/*@out@*/ void* rvalue,
526
/*@dependent@*/ ffi_raw* fake_avalue)
529
void **avalue = (void **)fake_avalue;
532
ecif.avalue = avalue;
534
/* If the return value is a struct and we don't have a return
535
value address then we need to make one */
536
if ((rvalue == NULL) && retval_on_stack(cif->rtype))
539
ecif.rvalue = alloca(cif->rtype->size);
543
ecif.rvalue = rvalue;
549
ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
550
cif->flags, ecif.rvalue, fn);
556
ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
557
cif->flags, ecif.rvalue, fn);
560
#endif /* X86_WIN32 */
567
#endif // !FFI_NO_RAW_API
568
//#endif // !__x86_64__