CALL和RET无法按预期工作

时间:2013-07-09 20:49:30

标签: stack return push nasm pop

我仍然经常迷失与堆栈相关的操作,在这种情况下,问题是 RET 指令,它会为 eip 寄存器弹出错误的地址。我使用 NASM ,我的代码如下所示:

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

也许我在ebp, edi, esi推动和弹出时夸大了一点(毕竟它们没有改变)但是即使我删除它们,ret指令仍会返回错误的地址( 77AE7094 )而不是 0040100A ,我调用第二个函数。

2 个答案:

答案 0 :(得分:1)

让我们看一下NASM为push dword -11生成的内容:

6AF5    push byte -0xb

所以NASM拿走了你的dword并将其替换为byte(由CPU提升为word,因为word是你的最小单位可以push进入堆栈。)为什么这样做?好吧,默认情况下启用了an optimizer,它会尝试优化即时通讯的大小。

由于您(可以理解)认为您已推送dword并稍后将{4}添加到esp,因此最终会出现不平衡的堆栈。

要阻止这种情况发生,您可以添加strict说明符,如:

push strict dword -11

或在组装时使用-O0选项。

答案 1 :(得分:1)

默认情况下,Windows使用stdcall调用约定,其中函数参数被压入堆栈(从右到左),被调用者清理堆栈。换句话说,当GetStdHandle返回时,堆栈将已经恢复到push dword -11指令之前。尝试删除add esp, 4行,看看是否修复了它。