为什么调用和跳转指令相对于下一条指令而不是当前指令使用位移?

在从英特尔文档中摘录的下表中,我们为操作码E8 cw 和E8 cd 提供了位移与下一条指令相关的信息。

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

为什么调用和跳转指令相对于下一条指令而不是当前指令使用位移?

tian150288 回答:为什么调用和跳转指令相对于下一条指令而不是当前指令使用位移?

TL:DR:无论如何,您都可以在解码期间找到指令的结尾,并设置下一条指令的解码。尽管有些CPU做出相对于下一条指令的结束之类的选择(对于ARM PC相对内存寻址),但CPU相对于当前指令的 end 进行相对寻址是很正常的。>

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


x86机器代码设计在80年代末与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时遇到的中断(例如)将最终前缀的地址作为异常返回地址,从而使段覆盖rep字符串指令在启用中断的情况下基本上不可用。 (因为执行将在没有rep或没有段替代的情况下恢复执行,以您为先)。参见x86 Program Counter abstracted from microarchitecture?和评论。


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

获取/解码已经必须在解码过程中找到指令的末尾(同时确定它是calljmp),因此指令的末尾/下一个地址-指令已经在内部可用。 call甚至必须将该值作为返回地址推入堆栈。

流水线RISC或完全未流水线的CPU也将使用该下一条指令地址从内存或I-cache提取下一条指令。但是实际上,8086预取与异步到一个小的预取缓冲区中。机器代码格式主要是在实现设计之前就在纸上进行设计的,因此,使这种与指令末尾相关的事情的常见原因可能是架构师考虑的。

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


只需重申一下,我只讲8086(内部与现代x86完全不同)的原因是它是 first 代,并且理解它有助于解释一些机器代码设计决策。 (例如,为什么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?

本文链接:https://www.f2er.com/3155819.html

大家都在问