【问题标题】:Does JZ not place a return address in the stack?JZ不会在堆栈中放置返回地址吗?
【发布时间】:2021-09-09 08:27:21
【问题描述】:

我正在阅读assembly code optimization manual 第 2.3 节常见编码陷阱 - 第 9 页

  1. 不匹配的 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 指令不是将返回地址存储在堆栈中吗? jmpjgjgejljle 等其他指令呢?

【问题讨论】:

  • 没有跳转指令推送返回地址。只有call 可以。
  • 当您绝对不想影响堆栈时,将控制权转移到不是函数结尾的地址更为常见关于需要什么堆栈调整/需要恢复寄存器的假设。需要多少这些指令的变体,以及使用哪些(组合)寄存器?
  • 如果您不确定指令的确切作用,请在 Intel 或 AMD 的手册中查找。 felixcloutier.com/x86/jcc 是从英特尔的 PDF 中抓取的。

标签: assembly x86


【解决方案1】:

不,它没有。 Call 指令将返回地址压入堆栈,jump 指令(包括条件跳转)不会。这就是调用和跳转的根本区别。

如果你想知道一个指令是做什么的,你应该总是参考它在官方文档中的描述,例如。 https://www.felixcloutier.com/x86/ 这是英特尔手册的 HTML 副本。 The description of jcc(包括je)没有提到推送返回地址,它告诉你它没有这样做。另一方面,the description of call 明确表示返回地址是推送的,并详细解释了它是如何完成的:

当执行近调用时,处理器将 EIP 寄存器的值(包含 CALL 指令之后的指令的偏移量)压入堆栈(稍后用作返回指令指针)。然后处理器跳转到目标操作数指定的当前代码段中的地址。

跳转指令通常用于在函数内转移控制,用于循环 (while)、条件执行 (if) 等结构。在大多数情况下,您不想返回到跳转,所以推送一个返回地址是没有用的,只需要你浪费额外的指令来从堆栈中删除它。

【讨论】:

    猜你喜欢
    • 2014-04-21
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 2016-01-10
    • 2022-01-16
    • 1970-01-01
    相关资源
    最近更新 更多