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: rkeuc...@allgeier.com Status: new Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=84268 >
On Thu Mar 28 13:42:02 2013, rkeuc...@allgeier.com 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?