1

我仍然经常迷失与堆栈相关的操作,在这种情况下,问题是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,我在这里调用第二个函数。

4

2 回答 2

2

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

于 2013-07-10T13:55:38.497 回答
-1

让我们看看 NASM 生成了什么push dword -11

6AF5    push byte -0xb

所以 NASM 取了你dword并用 a 替换它byte(CPU 将把它提升为 a word,因为 aword是你可以push进入堆栈的最小单位)。
为什么这样做?好吧,有一个默认启用的优化器,它将尝试优化立即数的大小。

因为你(可以理解)认为你推了 adword并且后来加了 4,esp你最终得到了一个不平衡的筹码。

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

push strict dword -11

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

于 2013-07-09T23:51:24.263 回答