www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 5591] New: EBX register not preserved when calling stdcall function pointer

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591

           Summary: EBX register not preserved when calling stdcall
                    function pointer
           Product: D
           Version: D2
          Platform: x86
        OS/Version: Windows
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: hypothermia.frost gmail.com



According to D's calling convention EBX register is preserved across function
calls, but when when I call a pointer to an extern(Windows) function, EBX gets
filled with some garbage value. It only happens the first time this function is
called, and the following times it behaves as expected!

The following sample code can be run to show it:

extern(Windows) void foo(int i){
    size_t ebx;
    asm { mov ebx,EBX; }
    std.stdio.writefln(" foo (EBX = %s,%s)",ebx,i);
    asm { mov EBX,10; }
}

alias extern(Windows) void function(int) fooT;

fooT bar;

void main(){
    size_t ebx=0;
    bar=&foo;

    asm { mov EBX,1; } //try normal call
    foo(2);
    asm { mov ebx,EBX; }
    std.stdio.writefln("EBX(after foo) = %x",ebx);    

    asm { mov EBX,3; } // now try pointer call for the 1st time
    bar(4);
    asm { mov ebx,EBX; }
    std.stdio.writefln("EBX(after bar) = %x",ebx);

    asm { mov EBX,5; } //2nd time
    bar(6);
    asm { mov ebx,EBX; }
    std.stdio.writefln("EBX(after bar 2nd time round) = %x",ebx);

    main2();
}

void main2(){ //and 3rd time!
    size_t ebx=0;
    asm { mov EBX,7; }
    bar(8);
    asm { mov ebx,EBX; }
    std.stdio.writefln("EBX(after bar 3rd time round in other func) = %x",ebx);
}

output:
 foo (EBX = 1,2)
EBX(after foo) = 1
 foo (EBX = 5518328,4)
EBX(after bar) = 5433f8
 foo (EBX = 5,6)
EBX(after bar 2nd time round) = 5
 foo (EBX = 7,8)
EBX(after bar 3rd time round in other func) = 7

What's going on with EBX on the 1st call?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 15 2011
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591




After doing some more tests I found out that if you compile with -O switch, the
code behaves as expected and output is:
 foo (EBX = 1,2)
EBX(after foo) = 1
 foo (EBX = 3,4)
EBX(after bar) = 3
...

Looks like it's a bug in DMD code gen without the -O switch.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 15 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591


hypothermia.frost gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|major                       |critical



After disassembly I found out that this code was generated(no -O switch):
//asm { mov EBX,3; } bar(4);
mov     ebx, 3
push    4
mov     ebx, large fs:2Ch
mov     esi, [ebx]
call    dword ptr [esi+4F4h]
mov     [ebp+var_20], ebx

//the next round ecx is used...
//asm { mov EBX,5; } bar(6);
mov     ebx, 5
push    6
mov     ecx, large fs:2Ch
mov     edx, [ecx]
call    dword ptr [edx+4F4h]
mov     [ebp+var_20], ebx

Why is DMD not preserving the EBX register in the first call? The worst thing
is that the compiler doesn't even know tha there's something in EBX... This
problem happened to me with when EBX had a this pointer and then DMD didn't
save it and after the function pointer call I got an exception!

I think this is a serious issue and should be looked at ASAP.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 16 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591


Don <clugdbug yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |wrong-code
                 CC|                            |clugdbug yahoo.com.au



Top priority for this one.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 16 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |bugzilla digitalmars.com
         Resolution|                            |INVALID



13:23:59 PST ---
This is a misunderstanding of the calling conventions. Examination of the asm
produced by the compiler shows that, indeed, EBX is preserved across all three
functions.

However, the compiler is not obliged to preserve the contents of EBX from
statement to statement within a function, which is what your code is expecting.

This is not a bug.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 17 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591




Ok, but as I said earlier this bug happened to me when the pointer call
happened in a member function call. The EBX register contained a 'this' pointer
and the compiler used it to load the function pointer. But after calling this
function pointer the compiler still thought EBX contained 'this' and I got an
Access Violation exception thrown when I tried to access a field from 'this'. I
saw this all using debugger and I traced the EBX change to the call of the
function pointer. And then how is this not a bug If the compiler thinks that
after using the EBX register, It has a value from previous use? Maybe Its hard
for you to understand what I'm trying to explain, but I will try to make an
example code to prove my point.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 17 2011
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5591




14:08:30 PST ---
If you can post a complete code snippet, and the obj2asm output of the asm
produced, that shows that EBX is not preserved across function calls, I can fix
it.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 17 2011