【问题标题】:What is the significance of operations on the register EAX having their own opcodes?寄存器 EAX 上的操作具有自己的操作码有什么意义?
【发布时间】:2016-10-27 10:14:36
【问题描述】:

如果您查看 cmptestaddsuband 等操作的文档,您会注意到涉及寄存器 EAX 及其 16 位和 8 位变体的操作因为第一个操作数有一个不同的操作码,它不同于这些指令的“一般情况”版本。

这个单独的操作码仅仅是一种节省代码空间的方法,它是不是比一般情况下的操作码更有效,或者它只是过去的一些遗物,出于兼容性原因不值得摆脱?

【问题讨论】:

  • 非常 早在 1976 年的设计目标就不同了。64KB 的 RAM 需要一条胳膊和一条腿,1MB 是只能梦想的未来。它确实持续了将近20年。以 AX 作为隐式操作数的指令少 1 个字节。

标签: assembly x86 machine-code instructions opcode


【解决方案1】:

这主要是过去的遗物,但也不完全“过时”。

在早期(,在Intel 8088 上),x86 寄存器集实际上更加专业化,就像其他当代 CISC 处理器一样。 (8088 的设计本身直接源自Intel 8080Zilog Z80 处理器。)也就是说,8 个寄存器并不像今天(功能上)都是通用的。有许多指令只适用于硬编码的寄存器。这意味着程序员经常发现自己在寄存器之间来回混洗值,以便为下一条指令正确设置。

EAX 是一个特别特别的寄存器。嗯,实际上,在那个时候,它被称为 AX,因为它只有 16 位并且还没有被E扩展到 32 位。 AX 是 A 累加器,并被 lots 的不同指令用作硬编码目标。 accumulator 是存储中间结果的寄存器——它“累积”了逻辑和算术运算的结果。几乎所有早期的微处理器都有一个累加器寄存器,其中许多强制你以这种方式使用累加器。 x86 架构在许多情况下更加灵活,但它仍然受到该设计的启发。关于 x86 寄存器集背后的逻辑的详细记录是 here

这些通用指令的特殊变体是该设计的结果。它们短(只有 1 个字节)、快速(主要是因为指令大小较小,但大概在早期也有硅级别的优化)与累加器寄存器中的值交互的方式。

所以是的,这正是一种节省代码空间的方法,是的,它仍然比一般情况编码更有效,正是 因为 对指令进行编码所需的字节更少。当然,考虑到我们显着更大的指令缓存和更快的内存读取速度,小代码大小在今天并不像 8088 那样重要,但它仍然有所作为。任何优秀的 x86 汇编程序员都知道尽可能使用这些基于累加器的短指令,许多编译器也这样做。这在内部循环中尤其重要,在这种情况下,减小代码大小对于确保所有内容都保留在缓存中至关重要。寄存器的使用甚至代码流通常都经过仔细的重新评估和重新排列,以尽可能多地保留累加器中的内容(即使在今天),以便可以使用这些简短、高效的操作码。

另请参阅:Peter Cordes's excellent "Tips for golfing in x86/x64 machine code",其中包含有关短格式编码的更多具体细节。

【讨论】:

  • 通常常量适合 imm8,add r/m32, imm8add eax, imm32 短。但是,如果您确实有一个很大的常量,例如 test 的位掩码,那么是的,您可以通过将数据保存在 eax 中来节省空间。因此,在eax 中保留内容的最佳选择并不总是使用最多的数据,而是与最大常量一起使用的数据。感谢威廉斯旺森关于寄存器命名/目的的文章的链接,顺便说一句。我将其添加到x86 tag wiki。 (现在有点臃肿了……)
  • 还相关:短格式编码设计选择和 8086 历史:Tips for golfing in x86/x64 machine code 上的这个答案有更多关于短格式编码的具体细节(包括op al, imm8xchg ax, reg 等等开)
猜你喜欢
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多