JZ、JMP等跳转指令是否会将返回地址压入栈中?
所有j开头的跳转指令(包括你提到的jz、jmp、jg、jge、jl、jle等)都不会将返回地址存入栈中,这类指令的逻辑和带返回的call指令完全不同。
各类跳转指令的运行逻辑
- 无条件跳转、条件跳转指令(所有
j开头且非call的指令):
这类指令的本质是直接修改指令指针寄存器(32位下为eip,64位下为rip)的值,执行时只会直接跳转到目标标签对应的地址执行后续代码,不会对栈做任何写入操作,也不会保存当前执行位置的相关信息,属于“无返回跳转”,一般用于函数内部的分支判断、循环跳转场景。 call类指令:
仅这类带返回的跳转指令会操作栈:执行时会先把call指令下一条指令的地址压入栈中,再修改指令指针跳转到目标函数地址。对应的ret指令的逻辑就是把当前栈顶存储的地址弹出,赋值给指令指针,回到call指令的下一个位置继续执行。
对应手册示例的错误原因
你提到的示例中,栈平衡被打破的逻辑完全符合上面的规则:
- 执行
push ebx后,栈顶存储的是ebx寄存器的原值 - 如果
ecx为0,触发jz Finished直接跳转到ret之前,这条路径没有执行对应的pop ebx - 执行
ret时,会把当前栈顶的内容(也就是之前压入的ebx原值)当作返回地址弹出赋值给eip,自然就会跳转到非法地址触发异常。
你产生混淆的核心是把普通跳转指令和call指令的逻辑搞混了,普通分支跳转不会操作栈,自然不会存入返回地址。
内容的提问来源于stack exchange,提问作者ADP
相关产品推荐
相关产品推荐

