diff options
author | tduehr <td@matasano.com> | 2014-07-01 12:55:06 -0500 |
---|---|---|
committer | tduehr <td@matasano.com> | 2014-07-01 12:55:06 -0500 |
commit | 822ee02b11e9407e0345a86cc6e0b298589ded29 (patch) | |
tree | 9ad8b4982fe54fb0f6f114f7fc2cabbb658b6880 | |
parent | e68b5ad692d5d79bbe0026d80aa71561ae667d15 (diff) | |
parent | 0499df7ed35cc3f4ffaee6a8f2ba2a09eef04fd4 (diff) | |
download | ffi-822ee02b11e9407e0345a86cc6e0b298589ded29.tar.gz |
Merge pull request #306 from larskanis/fix-stdcall
Fix stdcall ABI call convention.
-rw-r--r-- | ext/ffi_c/FunctionInfo.c | 4 | ||||
-rw-r--r-- | ext/ffi_c/Variadic.c | 4 | ||||
-rw-r--r-- | libtest/ClosureTest.c | 15 | ||||
-rw-r--r-- | spec/ffi/callback_spec.rb | 23 |
4 files changed, 42 insertions, 4 deletions
diff --git a/ext/ffi_c/FunctionInfo.c b/ext/ffi_c/FunctionInfo.c index b42b539..8085c87 100644 --- a/ext/ffi_c/FunctionInfo.c +++ b/ext/ffi_c/FunctionInfo.c @@ -119,7 +119,7 @@ fntype_initialize(int argc, VALUE* argv, VALUE self) ffi_status status; VALUE rbReturnType = Qnil, rbParamTypes = Qnil, rbOptions = Qnil; VALUE rbEnums = Qnil, rbConvention = Qnil, rbBlocking = Qnil; -#if defined(_WIN32) || defined(__WIN32__) +#if defined(X86_WIN32) VALUE rbConventionStr; #endif int i, nargs; @@ -181,7 +181,7 @@ fntype_initialize(int argc, VALUE* argv, VALUE self) fnInfo->ffiReturnType = fnInfo->returnType->ffiType; -#if (defined(_WIN32) || defined(__WIN32__)) && defined(FFI_STDCALL) +#if defined(X86_WIN32) rbConventionStr = (rbConvention != Qnil) ? rb_funcall2(rbConvention, rb_intern("to_s"), 0, NULL) : Qnil; fnInfo->abi = (rbConventionStr != Qnil && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0) ? FFI_STDCALL : FFI_DEFAULT_ABI; diff --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c index 51e9785..687e8bc 100644 --- a/ext/ffi_c/Variadic.c +++ b/ext/ffi_c/Variadic.c @@ -103,7 +103,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE VALUE retval = Qnil; VALUE convention = Qnil; VALUE fixed = Qnil; -#if defined(_WIN32) || defined(__WIN32__) +#if defined(X86_WIN32) VALUE rbConventionStr; #endif int i; @@ -116,7 +116,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE invoker->rbAddress = rbFunction; invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address; -#if (defined(_WIN32) || defined(__WIN32__)) && defined(FFI_STDCALL) +#if defined(X86_WIN32) rbConventionStr = rb_funcall2(convention, rb_intern("to_s"), 0, NULL); invoker->abi = (RTEST(convention) && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0) ? FFI_STDCALL : FFI_DEFAULT_ABI; diff --git a/libtest/ClosureTest.c b/libtest/ClosureTest.c index 64ea2b4..dfeabde 100644 --- a/libtest/ClosureTest.c +++ b/libtest/ClosureTest.c @@ -50,6 +50,21 @@ P(D, double); P(P, const void*); P(UL, unsigned long); +#if defined(_WIN32) && !defined(_WIN64) +bool __stdcall testClosureStdcall(long *a1, void __stdcall(*closure)(void *, long), long a2) { \ + void* sp_pre; + void* sp_post; + + asm volatile (" movl %%esp,%0" : "=g" (sp_pre)); + (*closure)(a1, a2); + asm volatile (" movl %%esp,%0" : "=g" (sp_post)); + + /* %esp before pushing parameters on the stack and after the call returns + * should be equal, if both sides respects the stdcall convention */ + return sp_pre == sp_post; +} +#endif + void testOptionalClosureBrV(void (*closure)(char), char a1) { if (closure) { diff --git a/spec/ffi/callback_spec.rb b/spec/ffi/callback_spec.rb index 139fef7..6e60d74 100644 --- a/spec/ffi/callback_spec.rb +++ b/spec/ffi/callback_spec.rb @@ -668,4 +668,27 @@ describe "Callback with " do }.should raise_error(ArgumentError) end + # + # Test stdcall convention with function and callback. + # This is Windows 32-bit only. + # + if FFI::Platform::OS =~ /windows|cygwin/ && FFI::Platform::ARCH == 'i386' + module LibTestStdcall + extend FFI::Library + ffi_lib TestLibrary::PATH + ffi_convention :stdcall + + callback :cbStdcall, [ :pointer, :long ], :void + attach_function :testCallbackStdcall, 'testClosureStdcall', [ :pointer, :cbStdcall, :long ], :bool + end + + it "stdcall convention" do + v = 0xdeadbeef + po = FFI::MemoryPointer.new :long + pr = proc{|a,i| v = a,i; i } + res = LibTestStdcall.testCallbackStdcall(po, pr, 0x7fffffff) + v.should == [po, 0x7fffffff] + res.should be_true + end + end end |