Assembly 打电话给don';I don’我没有按预期工作
我仍然经常对与堆栈相关的操作感到迷茫,在这种情况下,问题是RET指令,它会弹出一个错误的eip寄存器地址。我使用了NASM,我的代码如下所示:Assembly 打电话给don';I don’我没有按预期工作,assembly,x86,return,stack,nasm,Assembly,X86,Return,Stack,Nasm,我仍然经常对与堆栈相关的操作感到迷茫,在这种情况下,问题是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_GetSt
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,在这里我调用第二个函数。让我们看看NASM为推送dword-11生成了什么:
6AF5 push byte -0xb
因此,NASM将您的dword
替换为字节
(CPU会将其升级为字
,因为字
是您可以推到堆栈上的最小单元)。
它为什么这样做?嗯,有一个默认启用的,它将尝试优化即时消息的大小
由于您(可以理解)认为您推送了一个dword
,然后在esp
中添加了4,因此最终导致堆栈不平衡
要阻止这种情况发生,您可以添加strict
说明符,如下所示:
push strict dword -11
或者在组装时使用-O0
选项 让我们看看NASM为推送dword-11生成了什么:
6AF5 push byte -0xb
因此,NASM将您的dword
替换为字节
(CPU会将其升级为字
,因为字
是您可以推到堆栈上的最小单元)。
它为什么这样做?嗯,有一个默认启用的,它将尝试优化即时消息的大小
由于您(可以理解)认为您推送了一个dword
,然后在esp
中添加了4,因此最终导致堆栈不平衡
要阻止这种情况发生,您可以添加strict
说明符,如下所示:
push strict dword -11
或者在组装时使用-O0
选项 默认情况下,Windows使用stdcall
调用约定,将函数参数推送到堆栈上(从右到左),被调用方清理堆栈。换句话说,当GetStdHandle
返回时,堆栈将在push dword-11
指令之前恢复。尝试删除添加esp,4行,看看是否能解决问题。默认情况下,Windows使用stdcall
调用约定,函数参数被推送到堆栈上(从右到左),被调用方清理堆栈。换句话说,当GetStdHandle
返回时,堆栈将在push dword-11
指令之前恢复。尝试删除“添加esp,4”行,看看是否能解决问题。在《英特尔软件开发人员手册》第二卷中,“推送”指令:“操作数大小(16、32或64位)决定堆栈指针的递减量(2、4或8)。”假设这是32位代码,默认操作数大小将为32位,因此,CPU实际上会将其升级为dword推送字节-0xb
只是dword推送的立即数的压缩编码。没有66
操作数大小前缀,因此默认的32位操作数大小适用于32位模式,而不是任何模式下可用的最小值。无论如何,强制对dword push进行不太紧凑的编码在这里是没有用的。在《英特尔软件开发人员手册》第二卷中,“操作数大小(16、32或64位)决定堆栈指针的递减量(2、4或8)。”假设这是32位代码,默认操作数大小为32位,因此,CPU实际上会将其升级为dword推送字节-0xb
只是dword推送的立即数的压缩编码。没有66
操作数大小前缀,因此默认的32位操作数大小适用于32位模式,而不是任何模式下可用的最小值。无论如何,强制对dword push进行不太紧凑的编码在这里是没有用的。是的,事实上,我可以看到retn 4并删除了我自己的堆栈清理。谢谢,事实上,我可以看到retn 4并移除了我自己的堆栈清理。谢谢