【问题标题】:Why do call and jump instruction use a displacement relative to the next instruction, not current?为什么调用和跳转指令使用相对于下一条指令的位移,而不是当前指令?
【发布时间】:2020-03-02 09:26:21
【问题描述】:

在从英特尔文档中提取的下表中,我们有操作码 E8 cw 和 E8 cd 的位移相对于下一条指令。

为什么是下一条指令?为什么位移不是相对于call 指令本身?

【问题讨论】:

  • 历史硬件原因。您可以想象 CPU 已经获取了当前指令,因此 PC 已经指向下一条指令。如今,这当然无关紧要。替代解释:cpu 将继续执行下一条指令,因此偏移量表示偏离该指令的程度。
  • @Jester 在我正在测试的示例中,cpu 指向调用指令。它还没有获取它。
  • 当它需要使用偏移量时,它显然已经获取了它,因为该偏移量已嵌入指令中。
  • 这样做使最初的 8086 处理器更易于设计和实现。出于兼容性原因,该设计已被推进。 (例如,已经计算了下一条指令的地址才能用作返回地址。也可以使用您已经拥有的值!)

标签: assembly x86 intel machine-code relative-addressing


【解决方案1】:

TL:DR:无论如何,您在解码期间发现指令结束,并设置下一条指令的解码。 CPU 相对于当前指令的 end 进行相对寻址是很正常的,尽管有些 CPU 会做出不同的选择,例如相对于下一条指令的结尾(对于 ARM PC 相对内存寻址)。

Does Program Counter hold current address or the address of the next instruction?


x86 机器代码设计是在 70 年代后期与 8086 形成的,除了在扩展 ISA 时重新设计的东西(如 32/64 位 ModRM+SIB 寻址模式)。

原始的 8086 解码指令字节顺序(不一定是一次完整的指令),并且对前缀字节数或总指令长度没有上限。

认为 8086 避免了曾经需要保存指令的起始地址,即使是异常情况也是如此。例如,在现代 x86 上,#DE(除法异常)会推送错误指令的地址。但是on 8086 the exception frame has the address of the next instruction

8086 甚至有一个“错误”(或记录在案的设计缺陷),其中在执行 cs rep movsb 期间到达的中断(例如)将最终前缀的地址作为异常返回地址推送,从而在 @987654327 上进行段覆盖@-string 指令在启用中断的情况下基本上无法使用。 (因为在没有rep 或没有段覆盖的情况下将继续执行,无论你先放哪个)。请参阅x86 Program Counter abstracted from microarchitecture? 和 cmets。


当 8086 完成对call 指令的解码时,它不知道它从哪里开始。它唯一的参考点是call 指令的结尾。 因此,如果他们想在硬件中进行优化(不在任何地方保留解码起始地址),他们甚至别无选择.虽然理论上他们可以使用E8 call 操作码的地址(在任何前缀之后)作为锚点,但这可能需要额外的加法器或额外的硬件来单独记录。

Fetch/decode 已经必须在解码期间找到指令的结尾(同时确定它是 calljmp),因此指令结尾/下一条指令的地址已经内部可用。 call 甚至必须将该值作为返回地址压入堆栈。

流水线 RISC 或完全非流水线 CPU 也会使用该下一条指令地址从内存或 I-cache 中获取下一条指令。但实际上 8086 预取是异步进入一个小的预取缓冲区。机器代码格式主要是在设计实现之前在纸上设计的,所以这个使事情与指令结尾相关的常见原因可能是架构师的想法。

许多 ISA 的常见设计选择是相对于指令的结尾进行分支。


重申一下,我只谈论 8086(在内部 非常 与现代 x86 不同)的原因是它是 第一代,并且理解它有助于解释一些机器代码设计决策。 (例如,为什么 x86 在单字节 xchg [e/r]ax, reg 上花费 8 个操作码:因为 8086 没有 movsx 或 2 操作数 imul,并且需要或想要 AX 来处理很多东西。此外,代码大小是性能的主要瓶颈。)

现代 x86 只跟踪每条指令的地址,并且可以在解码 call rel32 时使用它。没什么大不了的。 Why do x86 jump/call instructions use relative displacements instead of absolute destinations?

【讨论】:

  • 关于cs rep movsb:您可以通过先放置rep 前缀并重复执行rep cs movsb 直到cx 包含0 来解决此问题。
猜你喜欢
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-08
  • 2021-05-18
  • 2013-12-06
  • 1970-01-01
  • 2014-09-17
相关资源
最近更新 更多