我正在阅读汇编代码优化手册第2.3节常见编码陷阱-第9页
不匹配的PUSH和POP指令。对于通过函数的所有可能路径,PUSH和POP指令的数量必须相等。示例:
push ebx test ecx, ecx jz Finished ... pop ebx Finished: ; Wrong! Label should be before pop ebx ret
这里,如果ECX为零,则不会再次弹出推送的EBX值。结果是RET指令将弹出EBX的前一个值,并跳转到错误的地址。
我的疑问是:jz
指令不是将返回地址存储在堆栈中吗?其他指令如jmp
、jg
、jge
、jl
、jle
等呢?
不,不是Call指令将返回地址推送到堆栈,jump(包括条件跳转(指令则不会。这就是呼叫和跳跃之间的根本区别。
如果你想知道指令的作用,你应该总是参考官方文件中的描述,例如。https://www.felixcloutier.com/x86/它是英特尔手册的HTML副本。jcc
(包括je
(的描述中没有提到推送返回地址,这告诉你它不推送。另一方面,call
的描述中明确说明了返回地址是推送的,并详细说明了如何推送:
执行近调用时,处理器将EIP寄存器的值(包含call指令后面的指令的偏移量(推送到堆栈上(稍后用作返回指令指针(。然后,处理器分支到目标操作数指定的当前代码段中的地址。
Jump指令通常用于在函数内传输控制,用于循环(while
(、条件执行(if
(等结构。在大多数此类情况下,您永远不想返回到跳转的位置,因此推送返回地址是没有用的,只需要浪费额外的指令就可以将其从堆栈中删除。