Thu Mar 28 15:58:57 2013: Request 84268 was acted upon.
Transaction: Correspondence added by BULKDD
Queue: Win32-API
Subject: Win32::API: Bug/Exception in call_asm_x86_msvc.asm
Broken in: (no value)
Severity: (no value)
Owner: Nobody
Requestors: [email protected]
Status: new
Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=84268 >
On Thu Mar 28 13:42:02 2013, [email protected] wrote:
> I get an exception in call_asm_x86_msvc.asm, raised at bad_esp.
> ESP
> and EBP do not match.
Your prototype is wrong. Either the func in the DLL is actually __cdecl because
it doesn't explicitly say __stdcall or WINAPI in each declaration and wasn't
compiled with -Gz and the default in Win32::API is always __stdcall unless
specified otherwise (this is the opposite of Visual C and GCC's defaults), or
it is a __stdcall which takes a different amount of args than you specified in
the prototype string.
>
> Using the C version works. Why is the ASM-
> Version the default for MSVC?
>
The inline assembly version was very inefficient compared to the ideal design,
the inline assembly version copied the same data between memory and register
2-4 times redundantly before writing it to memory for the final time, also the
call instruction appears 3 different times (but called only once) in the inline
assembly version instead of once. The C version (still used with GCC) doesn't
compare ESP to EBP to find wrong prototypes yet (not sure if the C version ever
will).
> I compiled a fresh perl for
> testing and debugging this.
> The called DLL is also built with MSVC
> 16 and uses WINAPI calling convention.
Are you sure?
>
> The signature is:
> Win32::API->Import("svapi32_vc100.dll", 'ULONG
> svapi_connect(LPVOID hsv,LPSTR s1,LPSTR s2,LPSTR s3,LPSTR s4,LPSTR
> s5,LPSTR s6,LPSTR s7,LPSTR s8,LPSTR s9, LPSTR s10)');
The above is probably a __cdecl in the DLL since __stdcall isn't specified
anywhere and -Gr and -Gz weren't used (-Gd wasn't used either, but it is on by
default). I made a test function below to try your prototype.
_______________________________________________
API_TEST_API ULONG svapi_connect(LPVOID hsv,LPSTR s1,LPSTR s2,LPSTR s3,
LPSTR s4,LPSTR s5,LPSTR s6,LPSTR s7,LPSTR s8,LPSTR s9, LPSTR s10) {
if(hsv == 0x0
&& atoi(s1) == 1
&& atoi(s2) == 2
&& atoi(s3) == 3
&& atoi(s4) == 4
&& atoi(s5) == 5
&& atoi(s6) == 6
&& atoi(s7) == 7
&& atoi(s8) == 8
&& atoi(s9) == 9
&& atoi(s10) == 10)
return 2;
else{
DebugBreak();
return 0;
}
}
___________________________________________________
this is fine, notice I changed the 1st parameter from LPVOID to ULONG (LPVOID
is a char * in Win32::API, not an opaque pointer as normally thought of LPVOID)
_______________________________________________
use Win32::API;
Win32::API->Import("api_test.dll", 'ULONG __cdecl svapi_connect(ULONG '
.'hsv,LPSTR s1,LPSTR s2,LPSTR s3,LPSTR s4,LPSTR s5,LPSTR s6,LPSTR s7,LPSTR s8,'
.'LPSTR s9, LPSTR s10)');
die "bad return" if svapi_connect(0..10) != 2;
_______________________________________________
This causes "Unhandled exception at 0x7c812afb in perl.exe: 0xC0000028: An
invalid or unaligned stack was encountered during an unwind operation." with
0.76_01.
_______________________________________________
use Win32::API;
Win32::API->Import("api_test.dll", 'ULONG svapi_connect(ULONG '
.'hsv,LPSTR s1,LPSTR s2,LPSTR s3,LPSTR s4,LPSTR s5,LPSTR s6,LPSTR s7,LPSTR s8,'
.'LPSTR s9, LPSTR s10)');
die "bad return" if svapi_connect(0..10) != 2;
_______________________________________________
I plan to change the RaiseException to a Perl catchable croak based on the
opinions in http://perlmonks.org/?node_id=1024423 in a future 0.76_02. Also I
might switch the RaiseException to a DebugBreak since RaiseException uses alot
of C autos and changes esp/ebp alot (but ebp sort of points to the incoming
args to RaiseException from Call_asm). Do you have another opinion of what to
do when there is a prototype mistake?