mirror of
https://github.com/python/cpython.git
synced 2026-01-06 23:42:34 +00:00
Sync the darwin/x86 port libffi with the copy in PyObjC. This fixes a number
of bugs in that port. The most annoying ones were due to some subtle differences between the document ABI and the actual implementation :-( (there are no python unittests that fail without this patch, but without it some of libffi's unittests fail).
This commit is contained in:
parent
74c3ea0a0f
commit
b4a6a566ff
2 changed files with 134 additions and 102 deletions
|
|
@ -35,6 +35,13 @@
|
|||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
#ifdef PyObjC_STRICT_DEBUGGING
|
||||
/* XXX: Debugging of stack alignment, to be removed */
|
||||
#define ASSERT_STACK_ALIGNED movdqa -16(%esp), %xmm0
|
||||
#else
|
||||
#define ASSERT_STACK_ALIGNED
|
||||
#endif
|
||||
|
||||
.text
|
||||
|
||||
.globl _ffi_prep_args
|
||||
|
|
@ -47,30 +54,41 @@ _ffi_call_SYSV:
|
|||
pushl %ebp
|
||||
.LCFI0:
|
||||
movl %esp,%ebp
|
||||
subl $8,%esp
|
||||
ASSERT_STACK_ALIGNED
|
||||
.LCFI1:
|
||||
/* Make room for all of the new args. */
|
||||
movl 16(%ebp),%ecx
|
||||
subl %ecx,%esp
|
||||
|
||||
ASSERT_STACK_ALIGNED
|
||||
|
||||
movl %esp,%eax
|
||||
|
||||
/* Place all of the ffi_prep_args in position */
|
||||
subl $8,%esp
|
||||
pushl 12(%ebp)
|
||||
pushl %eax
|
||||
call *8(%ebp)
|
||||
|
||||
ASSERT_STACK_ALIGNED
|
||||
|
||||
/* Return stack to previous state and call the function */
|
||||
addl $8,%esp
|
||||
addl $16,%esp
|
||||
|
||||
ASSERT_STACK_ALIGNED
|
||||
|
||||
call *28(%ebp)
|
||||
|
||||
/* Remove the space we pushed for the args */
|
||||
|
||||
/* XXX: return returns return with 'ret $4', that upsets the stack! */
|
||||
movl 16(%ebp),%ecx
|
||||
addl %ecx,%esp
|
||||
|
||||
|
||||
/* Load %ecx with the return type code */
|
||||
movl 20(%ebp),%ecx
|
||||
|
||||
|
||||
/* If the return value pointer is NULL, assume no return value. */
|
||||
cmpl $0,24(%ebp)
|
||||
jne retint
|
||||
|
|
@ -117,17 +135,47 @@ retlongdouble:
|
|||
|
||||
retint64:
|
||||
cmpl $FFI_TYPE_SINT64,%ecx
|
||||
jne retstruct
|
||||
jne retstruct1b
|
||||
/* Load %ecx with the pointer to storage for the return value */
|
||||
movl 24(%ebp),%ecx
|
||||
movl %eax,0(%ecx)
|
||||
movl %edx,4(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct1b:
|
||||
cmpl $FFI_TYPE_SINT8,%ecx
|
||||
jne retstruct2b
|
||||
movl 24(%ebp),%ecx
|
||||
movb %al,0(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct2b:
|
||||
cmpl $FFI_TYPE_SINT16,%ecx
|
||||
jne retstruct
|
||||
movl 24(%ebp),%ecx
|
||||
movw %ax,0(%ecx)
|
||||
jmp epilogue
|
||||
|
||||
retstruct:
|
||||
cmpl $FFI_TYPE_STRUCT,%ecx
|
||||
jne noretval
|
||||
/* Nothing to do! */
|
||||
|
||||
subl $4,%esp
|
||||
|
||||
ASSERT_STACK_ALIGNED
|
||||
|
||||
addl $8,%esp
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
noretval:
|
||||
epilogue:
|
||||
ASSERT_STACK_ALIGNED
|
||||
addl $8, %esp
|
||||
|
||||
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
switch (cif->rtype->type)
|
||||
{
|
||||
case FFI_TYPE_VOID:
|
||||
#if !defined(X86_WIN32)
|
||||
#if !defined(X86_WIN32) && !defined(X86_DARWIN)
|
||||
case FFI_TYPE_STRUCT:
|
||||
#endif
|
||||
case FFI_TYPE_SINT64:
|
||||
|
|
@ -154,7 +154,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
cif->flags = FFI_TYPE_SINT64;
|
||||
break;
|
||||
|
||||
#if defined X86_WIN32
|
||||
#if defined(X86_WIN32) || defined(X86_DARWIN)
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
if (cif->rtype->size == 1)
|
||||
|
|
@ -186,10 +186,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||
}
|
||||
|
||||
/* Darwin: The stack needs to be aligned to a multiple of 16 bytes */
|
||||
#if 0
|
||||
#if 1
|
||||
cif->bytes = (cif->bytes + 15) & ~0xF;
|
||||
#endif
|
||||
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +222,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|||
/*@dependent@*/ void **avalue)
|
||||
{
|
||||
extended_cif ecif;
|
||||
int flags;
|
||||
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
|
|
@ -238,20 +238,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|||
else
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
flags = cif->flags;
|
||||
if (flags == FFI_TYPE_STRUCT) {
|
||||
if (cif->rtype->size == 8) {
|
||||
flags = FFI_TYPE_SINT64;
|
||||
} else if (cif->rtype->size == 4) {
|
||||
flags = FFI_TYPE_INT;
|
||||
} else if (cif->rtype->size == 2) {
|
||||
flags = FFI_TYPE_INT;
|
||||
} else if (cif->rtype->size == 1) {
|
||||
flags = FFI_TYPE_INT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (cif->abi)
|
||||
{
|
||||
case FFI_SYSV:
|
||||
|
|
@ -260,8 +246,8 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|||
* block is a multiple of 16. Then add 8 to compensate for local variables
|
||||
* in ffi_call_SYSV.
|
||||
*/
|
||||
ffi_call_SYSV(ffi_prep_args, &ecif, ALIGN(cif->bytes, 16) +8,
|
||||
flags, ecif.rvalue, fn);
|
||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
|
||||
cif->flags, ecif.rvalue, fn);
|
||||
/*@=usedef@*/
|
||||
break;
|
||||
#ifdef X86_WIN32
|
||||
|
|
@ -281,8 +267,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
|||
|
||||
/** private members **/
|
||||
|
||||
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
|
||||
void** args, ffi_cif* cif);
|
||||
static void ffi_closure_SYSV (ffi_closure *)
|
||||
__attribute__ ((regparm(1)));
|
||||
#if !FFI_NO_RAW_API
|
||||
|
|
@ -290,83 +274,8 @@ static void ffi_closure_raw_SYSV (ffi_raw_closure *)
|
|||
__attribute__ ((regparm(1)));
|
||||
#endif
|
||||
|
||||
/* This function is jumped to by the trampoline */
|
||||
|
||||
static void
|
||||
ffi_closure_SYSV (closure)
|
||||
ffi_closure *closure;
|
||||
{
|
||||
// this is our return value storage
|
||||
long double res;
|
||||
|
||||
// our various things...
|
||||
ffi_cif *cif;
|
||||
void **arg_area;
|
||||
unsigned short rtype;
|
||||
void *resp = (void*)&res;
|
||||
void *args = __builtin_dwarf_cfa ();
|
||||
|
||||
cif = closure->cif;
|
||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
||||
|
||||
/* this call will initialize ARG_AREA, such that each
|
||||
* element in that array points to the corresponding
|
||||
* value on the stack; and if the function returns
|
||||
* a structure, it will re-set RESP to point to the
|
||||
* structure return address. */
|
||||
|
||||
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
|
||||
|
||||
(closure->fun) (cif, resp, arg_area, closure->user_data);
|
||||
|
||||
rtype = cif->flags;
|
||||
|
||||
if (!retval_on_stack(cif->rtype) && cif->flags == FFI_TYPE_STRUCT) {
|
||||
if (cif->rtype->size == 8) {
|
||||
rtype = FFI_TYPE_SINT64;
|
||||
} else {
|
||||
rtype = FFI_TYPE_INT;
|
||||
}
|
||||
}
|
||||
|
||||
/* now, do a generic return based on the value of rtype */
|
||||
if (rtype == FFI_TYPE_INT)
|
||||
{
|
||||
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
|
||||
}
|
||||
else if (rtype == FFI_TYPE_FLOAT)
|
||||
{
|
||||
asm ("flds (%0)" : : "r" (resp) : "st" );
|
||||
}
|
||||
else if (rtype == FFI_TYPE_DOUBLE)
|
||||
{
|
||||
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
|
||||
}
|
||||
else if (rtype == FFI_TYPE_LONGDOUBLE)
|
||||
{
|
||||
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
|
||||
}
|
||||
else if (rtype == FFI_TYPE_SINT64)
|
||||
{
|
||||
asm ("movl 0(%0),%%eax;"
|
||||
"movl 4(%0),%%edx"
|
||||
: : "r"(resp)
|
||||
: "eax", "edx");
|
||||
}
|
||||
#ifdef X86_WIN32
|
||||
else if (rtype == FFI_TYPE_SINT8) /* 1-byte struct */
|
||||
{
|
||||
asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
|
||||
}
|
||||
else if (rtype == FFI_TYPE_SINT16) /* 2-bytes struct */
|
||||
{
|
||||
asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*@-exportheader@*/
|
||||
static void
|
||||
static inline void
|
||||
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
||||
void **avalue, ffi_cif *cif)
|
||||
/*@=exportheader@*/
|
||||
|
|
@ -407,6 +316,81 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
|||
return;
|
||||
}
|
||||
|
||||
/* This function is jumped to by the trampoline */
|
||||
|
||||
static void
|
||||
ffi_closure_SYSV (closure)
|
||||
ffi_closure *closure;
|
||||
{
|
||||
// this is our return value storage
|
||||
long double res;
|
||||
|
||||
// our various things...
|
||||
ffi_cif *cif;
|
||||
void **arg_area;
|
||||
void *resp = (void*)&res;
|
||||
void *args = __builtin_dwarf_cfa ();
|
||||
|
||||
|
||||
cif = closure->cif;
|
||||
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
||||
|
||||
/* this call will initialize ARG_AREA, such that each
|
||||
* element in that array points to the corresponding
|
||||
* value on the stack; and if the function returns
|
||||
* a structure, it will re-set RESP to point to the
|
||||
* structure return address. */
|
||||
|
||||
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
|
||||
|
||||
(closure->fun) (cif, resp, arg_area, closure->user_data);
|
||||
|
||||
/* now, do a generic return based on the value of rtype */
|
||||
if (cif->flags == FFI_TYPE_INT)
|
||||
{
|
||||
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
|
||||
}
|
||||
else if (cif->flags == FFI_TYPE_FLOAT)
|
||||
{
|
||||
asm ("flds (%0)" : : "r" (resp) : "st" );
|
||||
}
|
||||
else if (cif->flags == FFI_TYPE_DOUBLE)
|
||||
{
|
||||
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
|
||||
}
|
||||
else if (cif->flags == FFI_TYPE_LONGDOUBLE)
|
||||
{
|
||||
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
|
||||
}
|
||||
else if (cif->flags == FFI_TYPE_SINT64)
|
||||
{
|
||||
asm ("movl 0(%0),%%eax;"
|
||||
"movl 4(%0),%%edx"
|
||||
: : "r"(resp)
|
||||
: "eax", "edx");
|
||||
}
|
||||
#if defined(X86_WIN32) || defined(X86_DARWIN)
|
||||
else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */
|
||||
{
|
||||
asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
|
||||
}
|
||||
else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */
|
||||
{
|
||||
asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (cif->flags == FFI_TYPE_STRUCT)
|
||||
{
|
||||
asm ("lea -8(%ebp),%esp;"
|
||||
"pop %esi;"
|
||||
"pop %edi;"
|
||||
"pop %ebp;"
|
||||
"ret $4");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
|
||||
|
||||
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue