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