This refactoring should make it easier to add new calling conventions.
Replace ffi_call_STDCALL and ffi_call_SYSV by a ffi_call_x86 function that cleans up the stack when FFI_SYSV is used, and does nothing for FFI_STDCALL. Remove libffi_msvc\win32.S, which is out of date and also unused; it was only used for building ctypes with the MingW compiler.
This commit is contained in:
parent
1797b7dbbc
commit
7757d7bb51
|
@ -148,27 +148,12 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/*@-declundef@*/
|
|
||||||
/*@-exportheader@*/
|
|
||||||
extern int
|
extern int
|
||||||
ffi_call_SYSV(void (*)(char *, extended_cif *),
|
ffi_call_x86(void (*)(char *, extended_cif *),
|
||||||
/*@out@*/ extended_cif *,
|
/*@out@*/ extended_cif *,
|
||||||
unsigned, unsigned,
|
unsigned, unsigned,
|
||||||
/*@out@*/ unsigned *,
|
/*@out@*/ unsigned *,
|
||||||
void (*fn)());
|
void (*fn)());
|
||||||
/*@=declundef@*/
|
|
||||||
/*@=exportheader@*/
|
|
||||||
|
|
||||||
/*@-declundef@*/
|
|
||||||
/*@-exportheader@*/
|
|
||||||
extern int
|
|
||||||
ffi_call_STDCALL(void (*)(char *, extended_cif *),
|
|
||||||
/*@out@*/ extended_cif *,
|
|
||||||
unsigned, unsigned,
|
|
||||||
/*@out@*/ unsigned *,
|
|
||||||
void (*fn)());
|
|
||||||
/*@=declundef@*/
|
|
||||||
/*@=exportheader@*/
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
@ -209,17 +194,9 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
|
||||||
{
|
{
|
||||||
#if !defined(_WIN64)
|
#if !defined(_WIN64)
|
||||||
case FFI_SYSV:
|
case FFI_SYSV:
|
||||||
/*@-usedef@*/
|
|
||||||
return ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
|
||||||
/*@=usedef@*/
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_STDCALL:
|
case FFI_STDCALL:
|
||||||
/*@-usedef@*/
|
return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes,
|
||||||
return ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
|
|
||||||
cif->flags, ecif.rvalue, fn);
|
cif->flags, ecif.rvalue, fn);
|
||||||
/*@=usedef@*/
|
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case FFI_SYSV:
|
case FFI_SYSV:
|
||||||
|
|
|
@ -1,243 +0,0 @@
|
||||||
/* -----------------------------------------------------------------------
|
|
||||||
win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
|
|
||||||
Copyright (c) 2001 John Beniton
|
|
||||||
Copyright (c) 2002 Ranjit Mathew
|
|
||||||
|
|
||||||
|
|
||||||
X86 Foreign Function Interface
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
``Software''), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define LIBFFI_ASM
|
|
||||||
#include <fficonfig.h>
|
|
||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
.globl ffi_prep_args
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
|
||||||
.balign 16
|
|
||||||
.globl _ffi_call_SYSV
|
|
||||||
|
|
||||||
_ffi_call_SYSV:
|
|
||||||
pushl %ebp
|
|
||||||
movl %esp,%ebp
|
|
||||||
|
|
||||||
#THe: save previous %esi, and store the current stack pointer in %esi
|
|
||||||
pushl %esi
|
|
||||||
movl %esp,%esi
|
|
||||||
|
|
||||||
# Make room for all of the new args.
|
|
||||||
movl 16(%ebp),%ecx
|
|
||||||
subl %ecx,%esp
|
|
||||||
|
|
||||||
movl %esp,%eax
|
|
||||||
|
|
||||||
# Place all of the ffi_prep_args in position
|
|
||||||
pushl 12(%ebp)
|
|
||||||
pushl %eax
|
|
||||||
call *8(%ebp)
|
|
||||||
|
|
||||||
# Return stack to previous state and call the function
|
|
||||||
addl $8,%esp
|
|
||||||
|
|
||||||
# FIXME: Align the stack to a 128-bit boundary to avoid
|
|
||||||
# potential performance hits.
|
|
||||||
|
|
||||||
call *28(%ebp)
|
|
||||||
|
|
||||||
# Remove the space we pushed for the args
|
|
||||||
movl 16(%ebp),%ecx
|
|
||||||
addl %ecx,%esp
|
|
||||||
|
|
||||||
sub %esp,%esi # calculate stack pointer difference
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Even if there is no space for the return value, we are
|
|
||||||
# obliged to handle floating-point values.
|
|
||||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
|
||||||
jne noretval
|
|
||||||
fstp %st(0)
|
|
||||||
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retint:
|
|
||||||
cmpl $FFI_TYPE_INT,%ecx
|
|
||||||
jne retfloat
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retfloat:
|
|
||||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
|
||||||
jne retdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstps (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retdouble:
|
|
||||||
cmpl $FFI_TYPE_DOUBLE,%ecx
|
|
||||||
jne retlongdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpl (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retlongdouble:
|
|
||||||
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
|
|
||||||
jne retint64
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpt (%ecx)
|
|
||||||
jmp epilogue
|
|
||||||
|
|
||||||
retint64:
|
|
||||||
cmpl $FFI_TYPE_SINT64,%ecx
|
|
||||||
jne retstruct
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
movl %edx,4(%ecx)
|
|
||||||
|
|
||||||
retstruct:
|
|
||||||
# Nothing to do!
|
|
||||||
|
|
||||||
noretval:
|
|
||||||
epilogue:
|
|
||||||
movl %esi,%eax # return the stack pointer detlta in %eax
|
|
||||||
popl %esi # restore previous %esi
|
|
||||||
movl %ebp,%esp
|
|
||||||
popl %ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
.ffi_call_SYSV_end:
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
|
||||||
.balign 16
|
|
||||||
.globl _ffi_call_STDCALL
|
|
||||||
|
|
||||||
_ffi_call_STDCALL:
|
|
||||||
pushl %ebp
|
|
||||||
movl %esp,%ebp
|
|
||||||
|
|
||||||
#THe: save previous %esi, and store the current stack pointer in %esi
|
|
||||||
pushl %esi
|
|
||||||
movl %esp,%esi
|
|
||||||
|
|
||||||
# Make room for all of the new args.
|
|
||||||
movl 16(%ebp),%ecx
|
|
||||||
subl %ecx,%esp
|
|
||||||
|
|
||||||
movl %esp,%eax
|
|
||||||
|
|
||||||
# Place all of the ffi_prep_args in position
|
|
||||||
pushl 12(%ebp)
|
|
||||||
pushl %eax
|
|
||||||
call *8(%ebp)
|
|
||||||
|
|
||||||
# Return stack to previous state and call the function
|
|
||||||
addl $8,%esp
|
|
||||||
|
|
||||||
# FIXME: Align the stack to a 128-bit boundary to avoid
|
|
||||||
# potential performance hits.
|
|
||||||
|
|
||||||
call *28(%ebp)
|
|
||||||
|
|
||||||
sub %esp,%esi # difference in stack
|
|
||||||
|
|
||||||
# stdcall functions pop arguments off the stack themselves
|
|
||||||
|
|
||||||
# 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 sc_retint
|
|
||||||
|
|
||||||
# Even if there is no space for the return value, we are
|
|
||||||
# obliged to handle floating-point values.
|
|
||||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
|
||||||
jne sc_noretval
|
|
||||||
fstp %st(0)
|
|
||||||
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retint:
|
|
||||||
cmpl $FFI_TYPE_INT,%ecx
|
|
||||||
jne sc_retfloat
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retfloat:
|
|
||||||
cmpl $FFI_TYPE_FLOAT,%ecx
|
|
||||||
jne sc_retdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstps (%ecx)
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retdouble:
|
|
||||||
cmpl $FFI_TYPE_DOUBLE,%ecx
|
|
||||||
jne sc_retlongdouble
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpl (%ecx)
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retlongdouble:
|
|
||||||
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
|
|
||||||
jne sc_retint64
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
fstpt (%ecx)
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retint64:
|
|
||||||
cmpl $FFI_TYPE_SINT64,%ecx
|
|
||||||
jne sc_retstruct
|
|
||||||
# Load %ecx with the pointer to storage for the return value
|
|
||||||
movl 24(%ebp),%ecx
|
|
||||||
movl %eax,0(%ecx)
|
|
||||||
movl %edx,4(%ecx)
|
|
||||||
|
|
||||||
sc_retstruct:
|
|
||||||
# Nothing to do!
|
|
||||||
|
|
||||||
sc_noretval:
|
|
||||||
sc_epilogue:
|
|
||||||
movl %esi,%eax # return the stack difference
|
|
||||||
popl %esi # restore previous %esi value
|
|
||||||
movl %ebp,%esp
|
|
||||||
popl %ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
.ffi_call_STDCALL_end:
|
|
|
@ -29,16 +29,16 @@
|
||||||
/* theller: almost verbatim translation from gas syntax to MSVC inline
|
/* theller: almost verbatim translation from gas syntax to MSVC inline
|
||||||
assembler code. */
|
assembler code. */
|
||||||
|
|
||||||
/* theller: ffi_call_SYSV and ffi_call_STDCALL now return an integer - the
|
/* theller: ffi_call_x86 now returns an integer - the difference of the stack
|
||||||
difference of the stack pointer before and after the function call. If
|
pointer before and after the function call. If everything is ok, zero is
|
||||||
everything is ok, zero is returned. If stdcall functions are passed the
|
returned. If stdcall functions are passed the wrong number of arguments,
|
||||||
wrong number of arguments, the difference will be nonzero. */
|
the difference will be nonzero. */
|
||||||
|
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#include <ffi_common.h>
|
#include <ffi_common.h>
|
||||||
|
|
||||||
__declspec(naked) int
|
__declspec(naked) int
|
||||||
ffi_call_SYSV(void (* prepfunc)(char *, extended_cif *), /* 8 */
|
ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */
|
||||||
extended_cif *ecif, /* 12 */
|
extended_cif *ecif, /* 12 */
|
||||||
unsigned bytes, /* 16 */
|
unsigned bytes, /* 16 */
|
||||||
unsigned flags, /* 20 */
|
unsigned flags, /* 20 */
|
||||||
|
@ -69,125 +69,20 @@ ffi_call_SYSV(void (* prepfunc)(char *, extended_cif *), /* 8 */
|
||||||
// FIXME: Align the stack to a 128-bit boundary to avoid
|
// FIXME: Align the stack to a 128-bit boundary to avoid
|
||||||
// potential performance hits.
|
// potential performance hits.
|
||||||
call [ebp + 28]
|
call [ebp + 28]
|
||||||
// Remove the space we pushed for the args
|
|
||||||
|
// Load ecif->cif->abi
|
||||||
|
mov ecx, [ebp + 12]
|
||||||
|
mov ecx, [ecx]ecif.cif
|
||||||
|
mov ecx, [ecx]ecif.cif.abi
|
||||||
|
|
||||||
|
cmp ecx, FFI_STDCALL
|
||||||
|
je noclean
|
||||||
|
// STDCALL: Remove the space we pushed for the args
|
||||||
mov ecx, [ebp + 16]
|
mov ecx, [ebp + 16]
|
||||||
add esp, ecx
|
add esp, ecx
|
||||||
|
// CDECL: Caller has already cleaned the stack
|
||||||
// XXX ASSERT THAT ESP IS THE SAME NOW THAN BEFORE!
|
noclean:
|
||||||
sub esi, esp
|
// Check that esp has the same value as before!
|
||||||
|
|
||||||
// Load %ecx with the return type code
|
|
||||||
mov ecx, [ebp + 20]
|
|
||||||
|
|
||||||
// If the return value pointer is NULL, assume no return value.
|
|
||||||
/*
|
|
||||||
Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
|
|
||||||
otherwise only one BYTE will be compared (instead of a DWORD)!
|
|
||||||
*/
|
|
||||||
cmp DWORD PTR [ebp + 24], 0
|
|
||||||
jne sc_retint
|
|
||||||
|
|
||||||
// Even if there is no space for the return value, we are
|
|
||||||
// obliged to handle floating-point values.
|
|
||||||
cmp ecx, FFI_TYPE_FLOAT
|
|
||||||
jne sc_noretval
|
|
||||||
// fstp %st(0)
|
|
||||||
fstp st(0)
|
|
||||||
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retint:
|
|
||||||
cmp ecx, FFI_TYPE_INT
|
|
||||||
jne sc_retfloat
|
|
||||||
// # Load %ecx with the pointer to storage for the return value
|
|
||||||
mov ecx, [ebp + 24]
|
|
||||||
mov [ecx + 0], eax
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retfloat:
|
|
||||||
cmp ecx, FFI_TYPE_FLOAT
|
|
||||||
jne sc_retdouble
|
|
||||||
// Load %ecx with the pointer to storage for the return value
|
|
||||||
mov ecx, [ebp+24]
|
|
||||||
// fstps (%ecx)
|
|
||||||
fstp DWORD PTR [ecx]
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retdouble:
|
|
||||||
cmp ecx, FFI_TYPE_DOUBLE
|
|
||||||
jne sc_retlongdouble
|
|
||||||
// movl 24(%ebp),%ecx
|
|
||||||
mov ecx, [ebp+24]
|
|
||||||
fstp QWORD PTR [ecx]
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
jmp sc_retlongdouble // avoid warning about unused label
|
|
||||||
sc_retlongdouble:
|
|
||||||
cmp ecx, FFI_TYPE_LONGDOUBLE
|
|
||||||
jne sc_retint64
|
|
||||||
// Load %ecx with the pointer to storage for the return value
|
|
||||||
mov ecx, [ebp+24]
|
|
||||||
// fstpt (%ecx)
|
|
||||||
fstp QWORD PTR [ecx] /* XXX ??? */
|
|
||||||
jmp sc_epilogue
|
|
||||||
|
|
||||||
sc_retint64:
|
|
||||||
cmp ecx, FFI_TYPE_SINT64
|
|
||||||
jne sc_retstruct
|
|
||||||
// Load %ecx with the pointer to storage for the return value
|
|
||||||
mov ecx, [ebp+24]
|
|
||||||
mov [ecx+0], eax
|
|
||||||
mov [ecx+4], edx
|
|
||||||
|
|
||||||
sc_retstruct:
|
|
||||||
// Nothing to do!
|
|
||||||
|
|
||||||
sc_noretval:
|
|
||||||
sc_epilogue:
|
|
||||||
mov eax, esi
|
|
||||||
pop esi // NEW restore: must be preserved across function calls
|
|
||||||
mov esp, ebp
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(naked) int
|
|
||||||
ffi_call_STDCALL(void (* prepfunc)(char *, extended_cif *), /* 8 */
|
|
||||||
extended_cif *ecif, /* 12 */
|
|
||||||
unsigned bytes, /* 16 */
|
|
||||||
unsigned flags, /* 20 */
|
|
||||||
unsigned *rvalue, /* 24 */
|
|
||||||
void (*fn)()) /* 28 */
|
|
||||||
{
|
|
||||||
_asm {
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
push esi // NEW: this register must be preserved across function calls
|
|
||||||
|
|
||||||
// XXX SAVE ESP NOW!
|
|
||||||
mov esi, esp
|
|
||||||
|
|
||||||
// Make room for all of the new args.
|
|
||||||
mov ecx, [ebp+16]
|
|
||||||
sub esp, ecx
|
|
||||||
|
|
||||||
mov eax, esp
|
|
||||||
|
|
||||||
// Place all of the ffi_prep_args in position
|
|
||||||
push [ebp + 12] // ecif
|
|
||||||
push eax
|
|
||||||
call [ebp + 8] // prepfunc
|
|
||||||
|
|
||||||
// Return stack to previous state and call the function
|
|
||||||
add esp, 8
|
|
||||||
// FIXME: Align the stack to a 128-bit boundary to avoid
|
|
||||||
// potential performance hits.
|
|
||||||
call [ebp + 28]
|
|
||||||
// stdcall functions pop arguments off the stack themselves
|
|
||||||
|
|
||||||
// XXX IS ESP NOW THE SAME AS BEFORE?
|
|
||||||
sub esi, esp
|
sub esi, esp
|
||||||
|
|
||||||
// Load %ecx with the return type code
|
// Load %ecx with the return type code
|
||||||
|
|
Loading…
Reference in New Issue