Thu Mar 28 17:42:02 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: open
 Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=84268 >


On Thu Mar 28 17:11:32 2013, rkeuc...@allgeier.com wrote:
> It's really stdcall. Sorry, I should have checked this..

Then why does it crash for you if it really is stdcall?

> 
> Maybe I
>    was biased because it worked in my old 5.14 ActiveState-Perl, which
>    probably used the C version of "call" or an old asm version.

Previous versions of Win32::API as far as I remember, didn't care if it was 
__cdecl or __stdcall, original esp from the XSUB is copied back in asm, "esp = 
*(void **)ebp; ebp = *(void **)esp; esp -= 4;" AKA "leave" or "mov esp, [ebp]; 
pop esp", so what the called C func left esp at was actually irrelevant (it can 
be esp == 0, and Call_asm didn't care).

> 
> I
>    recompiled Win32::API for getting WriteMemory(), which was missing
>    in the AS build.

OT: "unpack('P'," can read any memory, but you can't write to random memory 
from core Perl. The undocumented RtlMoveMemory in kernel32.dll in old 
Win32::APIs (0.68 and older) had to be cludgingly used before. Internet 
grapevine says RtlMoveMemory exists for VB Classic programmers to use. So I 
added a WriteMemory so that foreign memory allocators can more easily be used 
(some C func wants a LocalAlloc memory block to take ownership of and free when 
it wants, not malloc or Newx (PV buffer)). 

> 
> And others also use the DLL from C# so I
>    thought it would be stdcall..
> 
> 
> unsigned int __cdecl
>    svapi_connect(...)
> 
> push    ebp
> mov     ebp, esp
> push
>    0FFFFFFFEh
> push    offset stru_1006F560
> push    offset
>    __except_handler4
> mov     eax, large fs:0
> push    eax
> add
>    esp, 0FFFFFF68h
> mov     eax, ___security_cookie
> xor
>    [ebp+ms_exc.registration.ScopeTable], eax
> xor     eax, ebp
> mov
>    [ebp+var_24], eax
> push    ebx
> push    esi
> push    edi
> push
>    eax
> lea     eax, [ebp+ms_exc.registration]
> mov     large fs:0,
>    eax
> mov     [ebp+ms_exc.old_esp], esp
> 
> ...
> 
> mov     ecx,
>    [ebp+ms_exc.registration.Next]
> mov     large fs:0, ecx
> pop
>    ecx
> pop     edi
> pop     esi
> pop     ebx
> mov     ecx,
>    [ebp+var_24]
> xor     ecx, ebp        ; cookie
> call
>    @__security_check_cookie@4 ; __security_check_cookie(x)
> mov
>    esp, ebp
> pop     ebp
> retn
> 

This is a __cdecl function, "retn" would have a number after it if was a 
__stdcall.

> 
> > 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?
> 
> Yes, a DebugBreak() woud be nice
>    to find the reg mismatch, but most people i.e. using an
>    ActiveState-Build of Perl
> would not have debug syms.

You can sort-of, barely really, figure it out by just going to memory watch 
window, put "esp" as the address, set view to "4 byte integers" then do mental 
arthmitic (I think) to put back esp 4 bytes back (return address from 
DebugBreak()).

> 
> Maybe do
>    the DebugBreak() when IsDebuggerPresent() is true, else use croak.
>    You could call IsDebuggerPresent() when api.dll is loaded.
>    Thanks for your help and your work!
> 

I like that idea, I forgot IsDebuggerPresent exists. Thanks for the idea.

Reply via email to