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

问题描述 投票:1回答:1

在从英特尔文档中摘录的下表中,对于操作码E8 cw和E8 cd,位移是相对于下一条指令的。

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

call

assembly x86 intel machine-code relative-addressing
1个回答
0
投票

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

请参阅enter image description here


x86机器代码设计在80年代末与8086紧密相连,除了在扩展ISA时重新设计的东西(例如32/64位ModRM + SIB寻址模式)。>

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

I 思考

8086避免了[[ever需要保存指令的起始地址,]],即使是例外情况也是如此。例如,在现代x86上,Does Program Counter hold current address or the address of the next instruction?(除法异常)会推送错误指令的地址。但是#DE8086甚至有一个“ bug”(或已记录的设计缺陷),其中在执行on 8086 the exception frame has the address of the next instruction期间到达的中断(例如)将最终前缀的地址推送为异常返回地址,从而使段覆盖cs rep movsb -string指令在启用中断的情况下基本上不可用。 (因为执行将在没有rep或没有段覆盖的情况下恢复执行,以您为先)。参见rep和注释。


当8086完成对x86 Program Counter abstracted from microarchitecture?指令的解码时,它不知道从哪里开始。它唯一的参考点是call指令的结尾。

因此,如果他们想在硬件中进行优化(不将解码起始地址保留在任何地方),他们甚至别无选择。尽管从理论上讲,他们可以使用call操作码的地址(在任何前缀之后)作为锚点,但这可能需要额外的加法器或额外的硬件来单独记录。获取/解码已经必须在解码过程中找到指令的末尾(同时确定它是E8 callcall),所以指令的末尾/下一条指令的地址已经在内部可用。 jmp甚至必须将该值作为返回地址推入堆栈。

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

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


仅重申一下,我只讲8086(内部与现代x86有所不同)的原因是它是

first

代,理解它有助于解释一些机器代码设计决策。 (例如,为什么x86在单字节call上花费8个操作码:因为8086没有xchg [e/r]ax, reg或2运算符movsx,并且需要或希望使用AX来处理很多东西。此外,代码大小也是性能的主要瓶颈。)现代x86仅跟踪每个指令的地址,并且在解码imul时可以使用该地址。没有大碍。 call rel32
© www.soinside.com 2019 - 2024. All rights reserved.