ali
ali

Reputation: 11045

CALL and RET don't work as expected

I still get lost with the stack related operations often and in this case the problem is the RET instruction, which pops a wrong address for the eip register. I use NASM and my code looks like this:

start:
    call GiveMeAHandler
    call GetCommandLine
    ret

GiveMeAHandler:
    push ebp
    mov ebp, esp
    push edi
    push esi
    push dword -11
    call dword [F_GetStdHandle] ; It executes correctly and returns
    mov [StdHandler], eax ; StdHandler is stored in BSS
    add esp, 4
    pop esi
    pop edi
    pop ebp
    ret ; This returns to some weird address

GetCommandLine:
    ; ...
    ; I don't get here because the function above wrong return

Maybe I have exaggerated a little with the ebp, edi, esi pushing and popping (they are not altered after all) but even if I remove them the ret instruction still returns a wrong address (77AE7094) instead of 0040100A, where I call the second function.

Upvotes: 1

Views: 270

Answers (2)

Drew McGowen
Drew McGowen

Reputation: 11706

By default, Windows uses the stdcall calling convention, where function arguments are pushed onto the stack (right to left), and the callee cleans up the stack. In other words, when GetStdHandle returns, the stack will already be restored to before your push dword -11 instruction. Try removing the add esp, 4 line and see if that fixes it.

Upvotes: 2

Michael
Michael

Reputation: 58427

Let's look at what NASM generates for push dword -11:

6AF5    push byte -0xb

So NASM took your dword and replaced it with a byte (which will be promoted to a word by the CPU, since a word is the smallest unit you can push onto the stack).
Why did it do that? Well, there's an optimizer which is enabled by default, and which will attempt to optimize the size of immediates.

Since you (understandably) thought you had pushed a dword and later add 4 to esp you end up with an unbalanced stack.

To stop this from happening you can either add a strict specifier, as in:

push strict dword -11

Or use the -O0 option when assembling.

Upvotes: -1

Related Questions