rax
AFAIK x86-64 在从 Intel x86 ( ,rcx
等)派生的寄存器中添加了许多通用寄存器,称为r8
- r15
。
他们为什么这样命名新的寄存器?为什么不遵循现有的命名约定并称它们为rfx
,rgx
...?
rax
AFAIK x86-64 在从 Intel x86 ( ,rcx
等)派生的寄存器中添加了许多通用寄存器,称为r8
- r15
。
他们为什么这样命名新的寄存器?为什么不遵循现有的命名约定并称它们为rfx
,rgx
...?
对 CPU 寄存器进行编号是常态,几乎所有处理器都这样做。然而,8086 处理器很古老,早在 1976 年他们的晶体管预算就非常有限。实现一个只有 20,000 个有源晶体管的 16 位处理器是一项相当艰巨的任务。他们减少的一种方法是为寄存器提供专用功能。那时给它们起名字而不是数字是有意义的,暗示它们的用法。另一个影响是它旨在提供与 8080 处理器的一定程度的兼容性,它还具有具有专用功能的命名寄存器。
完全相反的设计是摩托罗拉 68000,三年后设计的采用更先进的工艺技术,允许双倍的晶体管预算。一个非常正交的设计,(几乎)每个寄存器都可以在任何指令中自由使用。并且与早期设计不兼容。它有编号的寄存器(D0-D7 和 A0-A7)。
x86 架构的扩展再次使用编号寄存器,如 R8 到 R15、MM0 到 MM7、XMM0-15、YMM0-15 等。
为什么不遵循现有的命名约定
因为低 8 位名称不是任意序列或约定,所以它们是根据特定目的命名的。r8-r15 没有任何特定用途,几乎没有隐含用途或特殊性。所有最初的 8 个寄存器都至少有一条指令隐式使用该寄存器。有关名称的含义,请参见https://www.swansontec.com/sregisters.html 。(EDX=data 可能是一个反义词,但 A 代表累加器和 C 代表计数器显然不是巧合)。
AMD64 是在 2000 年左右设计的,旨在尽可能正交,因此它是一个更好的编译器目标(当值在哪个寄存器中无关紧要时,编译器会更容易)。
早在 2000 年就已经确立,在没有什么特别之处的情况下,有编号的寄存器是正常的;所有 RISC ISA 和许多最近的 CISC ISA 都这样做。(见@Hans的回答)
早期的 x86 扩展(尤其是 186 / 386)通过添加一个不需要 EAX/AX的多操作数使 ISA 比 8086 更加正交imul r,r/m
,imul r, r/m, imm
movsx
作为非 EAX 版本cbw
(以及一条指令中的 8->32) ,尤其是 32 位寻址模式,允许任何寄存器用于任何内容,而不仅仅是[bx|bp] + [si|di] + disp0/8/16
. 但是没有添加新的寄存器,并且在添加更灵活的方式时没有删除隐式使用,因此在现代 x86 中,名称只是对隐式使用的提醒,而不是您必须使用每个寄存器的用途。
Dave Christie(AMD 的 AMD64 CPU 架构师) 在 2000-sep-15 的 x86-64.org 邮件列表上发布了此内容,以回复有关重命名旧寄存器 R0..R7 或命名高位寄存器 UAX / 的讨论……
弄清楚如何最好地命名寄存器实际上是进行寄存器扩展最困难的部分之一。保留 AX、BX 等低八位命名法的主要动机正是 Honza 所建议的 [在线程的较早消息中] - 大多数这些寄存器都有各种特殊用途,经验丰富的 x86 程序员非常熟悉,并且实际上体现在助记符上(A=accumulator, C=Count, SP=Stack Pointer, SI=Source Index, etc),帮助新手记住这些特殊用途。
这种特殊情况功能的一些工件反映在高位寄存器中,但仅适用于指令编码1——没有反映任何特殊功能,因此使用 UAX 等确实会产生误导。我们最终命名他们 R8-R15,承认有些人可能更愿意将较低的集合视为 R0-R7,但在我们的文档中从不使用这样的名称,以避免混淆。
汇编器可以自由定义这样的别名,尽管正如 Alex 指出的那样,我们认为如果同时允许两组名称,它会增加混淆和错误的机会。因此,如果定义了此类别名,我建议以允许程序员仅启用一组或另一组的方式完成。
(我添加的脚注:高位寄存器的特殊情况是在寻址模式编码中:R13 就像 RBP,不能是没有位移的基数。R12 就像 RSP 并且需要一个 SIB 字节。但与 RSP 不同的是,它可以是索引。请参阅我关于为什么 rbp 和 rsp 称为通用寄存器?)的答案的底部
x86-64.org 邮件列表存档在 gcc 和 (Linux) 内核开发人员以及 AMD64 架构师之间进行了一些有趣的讨论。如果您曾经想知道 x86-64 System V 调用约定是如何设计的,以及为什么它会传递前几个参数rdi, rsi, rdx, rcx
,那么 Jan (Honza) Hubicka 是基于(动态)指令计数和(静态) SPECint 的代码大小,使用当时的 gcc 构建,可能喜欢内联rep movs
小副本。请参阅为什么 Windows64 使用与 x86-64 上的所有其他操作系统不同的调用约定?用于邮件列表存档链接和更多详细信息。
在那次讨论中没有人建议使用诸如rfx
之类的字母。
这本来是一种字母汤,一个单独的命名方案使得区分新旧寄存器非常容易。这让您可以看到指令何时需要 REX 前缀(代码大小越小越好)。egmov eax, edx
比 . 短 1 个字节mov eax, r8d
。
而且,REX 前缀意味着您无法访问 AH/CH/DH/BH,因此如果您使用这些字节注册,您必须跟踪您在做什么。movzx r8d, bl
(例如,您可以使用/ movzx ecx, bh
/从 qword 解压缩字节shr rbx, 16
,但不能movzx r9d, bh
(REX.B 用于高 reg)或movsx rcx, bh
(REX.W 用于 64 位目标。)
易于查看/记住哪些 regs 是新的对内核开发人员也很有帮助,例如,在来自 32 位用户空间的内核入口点中,有价值的用户空间状态仅在 eax..esi 中,而且很容易要记住 r8-r15 是 32 位代码无法触及的“新”寄存器。
这在现在看来似乎微不足道,但是当 ISA 是新的时,所有的 asm 程序员都必须学习它。AMD 的架构师致力于 AMD64 的命名方案,IMO 做得很好。
有关的:
lahf
/sahf
存在是为了更有效的 8080 兼容性。cmpxchg16b
.)为什么不遵循现有的命名约定并将它们称为 rfx、rgx ...?
除了给出的答案:您假设 x86 CPU 的寄存器被命名为 ABCD-... 是不正确的:
8086 是在 M68000 之前推出的,几乎所有在 M68000 之前的 CPU 的寄存器名称都是按功能命名的。
8086 也是如此:
另请注意,寄存器的名称不是AX-BX-CX-DX,而是AX-CX-DX-BX!
功能说明:
add dl, bl
)执行任何操作。相反,“ A
”寄存器是操作的隐式“左”操作数:Z80 指令“ add 30
”将add al, 30
在 x86 语法中写为“”。ax
旨在用于这种情况。并且某些操作 ( mul
) 仍然隐式使用了ax
寄存器。loop
和rep
- 所以它用于计数。bx
寄存器可用于寻址内存(例如mov ax, [bx+40]
),而 x86 CPU 无法使用寄存器ax
,cx
或dx
寻址内存(与 32 位变体不同eax
,ecx
并且edx
- 但 8086 没有 32 位寄存器)。所以bx
可能会在内存中保存一些数据结构的基地址,您可以访问该结构中的数据。