Ale*_*der 2 x86 assembly intel machine-code relative-addressing
在从英特尔文档中摘录的下表中,我们为操作码E8 cw和E8 cd提供了位移与下一条指令相关的信息。
为什么下一条指令?为什么位移不相对于call指令本身?
TL:DR:无论如何,您都可以在解码期间找到指令的结尾,并设置下一条指令的解码。CPU相对于当前指令的末尾进行相对寻址是很正常的,尽管有些CPU会做出不同的选择,例如相对于下一条指令的末尾(对于ARM PC相对内存寻址)。
x86机器代码设计在80年代末与8086紧密相关,但在扩展ISA时需要重新设计的东西(例如32/64位ModRM + SIB寻址模式)除外。
原始的8086依次解码指令字节(不必一次解码整个指令),并且前缀字节数或总指令长度没有上限。
我认为 8086避免了即使有例外也无需保存指令的起始地址。例如,在现代的x86上#DE(除法异常)推送错误指令的地址。但是在8086上,异常帧具有下一条指令的地址。
8086甚至存在一个“错误”(或已记录的设计缺陷),其中在执行过程中到达的中断cs rep movsb(例如)将最终前缀的地址推送为异常返回地址,这使得在rep启用中断的情况下,对-string指令的段覆盖基本上不可用。(因为执行将在没有rep或没有段覆盖的情况下恢复执行,以您为先)。看到从微体系结构抽象的x86程序计数器?和评论。
8086完成对call指令的解码后,不知道从哪里开始。它具有的唯一参考点是call指令的结尾。 因此,如果他们想在硬件中进行优化(不将解码起始地址保留在任何地方),他们甚至别无选择。尽管从理论上讲,他们可以将E8 call操作码的地址(在任何前缀之后)用作锚点,但这可能需要额外的加法器或额外的硬件来单独记录。
提取/解码已经必须在解码期间找到指令的末尾(同时弄清楚它是a call或jmp),因此指令的末尾/下一指令的地址已经在内部可用。 call甚至必须将该值压入堆栈作为返回地址。
流水线RISC或完全未流水线的CPU也将使用该下一条指令地址从内存或I-cache中获取下一条指令。但是实际上,8086预取与异步到一个小的预取缓冲区中。机器代码格式主要是在实现设计之前就在纸上进行设计的,因此,使这种与指令末尾相关的事情的常见原因可能是架构师考虑的。
对于许多ISA来说,相对于指令的结尾进行分支是一种常见的设计选择。
重申一下,我只讲8086(内部与现代x86有很大不同)的原因是它是第一代产品,理解它有助于解释某些机器代码设计决策。(例如,为什么x86在单字节上花8个操作码xchg [e/r]ax, reg:因为8086没有movsx或2操作数imul,并且需要或想要AX来做很多事情。而且,代码大小也是性能的主要瓶颈。)
现代的x86只是跟踪每个指令的地址,并且可以在解码时使用它call rel32。没什么大不了的。 为什么x86跳转/调用指令使用相对位移而不是绝对目的地?
| 归档时间: |
|
| 查看次数: |
60 次 |
| 最近记录: |