Commit b4a6a566 authored by Ronald Oussoren's avatar Ronald Oussoren

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).
parent 74c3ea0a
...@@ -35,6 +35,13 @@ ...@@ -35,6 +35,13 @@
#include <fficonfig.h> #include <fficonfig.h>
#include <ffi.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 .text
.globl _ffi_prep_args .globl _ffi_prep_args
...@@ -47,30 +54,41 @@ _ffi_call_SYSV: ...@@ -47,30 +54,41 @@ _ffi_call_SYSV:
pushl %ebp pushl %ebp
.LCFI0: .LCFI0:
movl %esp,%ebp movl %esp,%ebp
subl $8,%esp
ASSERT_STACK_ALIGNED
.LCFI1: .LCFI1:
/* Make room for all of the new args. */ /* Make room for all of the new args. */
movl 16(%ebp),%ecx movl 16(%ebp),%ecx
subl %ecx,%esp subl %ecx,%esp
ASSERT_STACK_ALIGNED
movl %esp,%eax movl %esp,%eax
/* Place all of the ffi_prep_args in position */ /* Place all of the ffi_prep_args in position */
subl $8,%esp
pushl 12(%ebp) pushl 12(%ebp)
pushl %eax pushl %eax
call *8(%ebp) call *8(%ebp)
ASSERT_STACK_ALIGNED
/* Return stack to previous state and call the function */ /* Return stack to previous state and call the function */
addl $8,%esp addl $16,%esp
ASSERT_STACK_ALIGNED
call *28(%ebp) 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 movl 16(%ebp),%ecx
addl %ecx,%esp addl %ecx,%esp
/* Load %ecx with the return type code */ /* Load %ecx with the return type code */
movl 20(%ebp),%ecx movl 20(%ebp),%ecx
/* If the return value pointer is NULL, assume no return value. */ /* If the return value pointer is NULL, assume no return value. */
cmpl $0,24(%ebp) cmpl $0,24(%ebp)
jne retint jne retint
...@@ -117,17 +135,47 @@ retlongdouble: ...@@ -117,17 +135,47 @@ retlongdouble:
retint64: retint64:
cmpl $FFI_TYPE_SINT64,%ecx cmpl $FFI_TYPE_SINT64,%ecx
jne retstruct jne retstruct1b
/* Load %ecx with the pointer to storage for the return value */ /* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx movl 24(%ebp),%ecx
movl %eax,0(%ecx) movl %eax,0(%ecx)
movl %edx,4(%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: retstruct:
cmpl $FFI_TYPE_STRUCT,%ecx
jne noretval
/* Nothing to do! */ /* Nothing to do! */
subl $4,%esp
ASSERT_STACK_ALIGNED
addl $8,%esp
movl %ebp, %esp
popl %ebp
ret
noretval: noretval:
epilogue: epilogue:
ASSERT_STACK_ALIGNED
addl $8, %esp
movl %ebp,%esp movl %ebp,%esp
popl %ebp popl %ebp
ret ret
......
...@@ -140,7 +140,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) ...@@ -140,7 +140,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
switch (cif->rtype->type) switch (cif->rtype->type)
{ {
case FFI_TYPE_VOID: case FFI_TYPE_VOID:
#if !defined(X86_WIN32) #if !defined(X86_WIN32) && !defined(X86_DARWIN)
case FFI_TYPE_STRUCT: case FFI_TYPE_STRUCT:
#endif #endif
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
...@@ -154,7 +154,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) ...@@ -154,7 +154,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
cif->flags = FFI_TYPE_SINT64; cif->flags = FFI_TYPE_SINT64;
break; break;
#if defined X86_WIN32 #if defined(X86_WIN32) || defined(X86_DARWIN)
case FFI_TYPE_STRUCT: case FFI_TYPE_STRUCT:
if (cif->rtype->size == 1) if (cif->rtype->size == 1)
...@@ -186,10 +186,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) ...@@ -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 */ /* Darwin: The stack needs to be aligned to a multiple of 16 bytes */
#if 0 #if 1
cif->bytes = (cif->bytes + 15) & ~0xF; cif->bytes = (cif->bytes + 15) & ~0xF;
#endif #endif
return FFI_OK; return FFI_OK;
} }
...@@ -221,7 +222,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, ...@@ -221,7 +222,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
/*@dependent@*/ void **avalue) /*@dependent@*/ void **avalue)
{ {
extended_cif ecif; extended_cif ecif;
int flags;
ecif.cif = cif; ecif.cif = cif;
ecif.avalue = avalue; ecif.avalue = avalue;
...@@ -238,20 +238,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, ...@@ -238,20 +238,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
else else
ecif.rvalue = rvalue; 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) switch (cif->abi)
{ {
case FFI_SYSV: case FFI_SYSV:
...@@ -260,8 +246,8 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, ...@@ -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 * block is a multiple of 16. Then add 8 to compensate for local variables
* in ffi_call_SYSV. * in ffi_call_SYSV.
*/ */
ffi_call_SYSV(ffi_prep_args, &ecif, ALIGN(cif->bytes, 16) +8, ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
flags, ecif.rvalue, fn); cif->flags, ecif.rvalue, fn);
/*@=usedef@*/ /*@=usedef@*/
break; break;
#ifdef X86_WIN32 #ifdef X86_WIN32
...@@ -281,8 +267,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, ...@@ -281,8 +267,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
/** private members **/ /** 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 *) static void ffi_closure_SYSV (ffi_closure *)
__attribute__ ((regparm(1))); __attribute__ ((regparm(1)));
#if !FFI_NO_RAW_API #if !FFI_NO_RAW_API
...@@ -290,6 +274,48 @@ static void ffi_closure_raw_SYSV (ffi_raw_closure *) ...@@ -290,6 +274,48 @@ static void ffi_closure_raw_SYSV (ffi_raw_closure *)
__attribute__ ((regparm(1))); __attribute__ ((regparm(1)));
#endif #endif
/*@-exportheader@*/
static inline void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
void **avalue, ffi_cif *cif)
/*@=exportheader@*/
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if (retval_on_stack(cif->rtype)) {
*rvalue = *(void **) argp;
argp += 4;
}
p_argv = avalue;
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(int) - 1) & (unsigned) argp) {
argp = (char *) ALIGN(argp, sizeof(int));
}
z = (*p_arg)->size;
/* because we're little endian, this is what it turns into. */
*p_argv = (void*) argp;
p_argv++;
argp += z;
}
return;
}
/* This function is jumped to by the trampoline */ /* This function is jumped to by the trampoline */
static void static void
...@@ -302,10 +328,10 @@ ffi_closure_SYSV (closure) ...@@ -302,10 +328,10 @@ ffi_closure_SYSV (closure)
// our various things... // our various things...
ffi_cif *cif; ffi_cif *cif;
void **arg_area; void **arg_area;
unsigned short rtype;
void *resp = (void*)&res; void *resp = (void*)&res;
void *args = __builtin_dwarf_cfa (); void *args = __builtin_dwarf_cfa ();
cif = closure->cif; cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*)); arg_area = (void**) alloca (cif->nargs * sizeof (void*));
...@@ -319,94 +345,52 @@ ffi_closure_SYSV (closure) ...@@ -319,94 +345,52 @@ ffi_closure_SYSV (closure)
(closure->fun) (cif, resp, arg_area, closure->user_data); (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 */ /* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT) if (cif->flags == FFI_TYPE_INT)
{ {
asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
} }
else if (rtype == FFI_TYPE_FLOAT) else if (cif->flags == FFI_TYPE_FLOAT)
{ {
asm ("flds (%0)" : : "r" (resp) : "st" ); asm ("flds (%0)" : : "r" (resp) : "st" );
} }
else if (rtype == FFI_TYPE_DOUBLE) else if (cif->flags == FFI_TYPE_DOUBLE)
{ {
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
} }
else if (rtype == FFI_TYPE_LONGDOUBLE) else if (cif->flags == FFI_TYPE_LONGDOUBLE)
{ {
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
} }
else if (rtype == FFI_TYPE_SINT64) else if (cif->flags == FFI_TYPE_SINT64)
{ {
asm ("movl 0(%0),%%eax;" asm ("movl 0(%0),%%eax;"
"movl 4(%0),%%edx" "movl 4(%0),%%edx"
: : "r"(resp) : : "r"(resp)
: "eax", "edx"); : "eax", "edx");
} }
#ifdef X86_WIN32 #if defined(X86_WIN32) || defined(X86_DARWIN)
else if (rtype == FFI_TYPE_SINT8) /* 1-byte struct */ else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */
{ {
asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax"); asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
} }
else if (rtype == FFI_TYPE_SINT16) /* 2-bytes struct */ else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */
{ {
asm ("movswl (%0),%%eax" : : "r" (resp) : "eax"); asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
} }
#endif #endif
}
/*@-exportheader@*/
static void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
void **avalue, ffi_cif *cif)
/*@=exportheader@*/
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if (retval_on_stack(cif->rtype)) {
*rvalue = *(void **) argp;
argp += 4;
}
p_argv = avalue; else if (cif->flags == FFI_TYPE_STRUCT)
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{ {
size_t z; asm ("lea -8(%ebp),%esp;"
"pop %esi;"
/* Align if necessary */ "pop %edi;"
if ((sizeof(int) - 1) & (unsigned) argp) { "pop %ebp;"
argp = (char *) ALIGN(argp, sizeof(int)); "ret $4");
} }
z = (*p_arg)->size;
/* because we're little endian, this is what it turns into. */
*p_argv = (void*) argp;
p_argv++;
argp += z;
}
return;
} }
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment