翻译:x86寄存器的历史

EAX x86 Register: Meaning and History
[译] 简明 x86 汇编指南(2017)

EAX的故事

到底什么是EAX,名字怎么来的。


通常,x86教程不会花太多时间解释设计和命名决策的历史背景。在学习x86汇编时,你通常会被告知类似这样的话:这是EAX,它是一个寄存器,用它就行。

那么,这些字母到底代表什么?E–A–X。

恐怕没有简单的答案!我们得回到1972年……

8008 :A

在1972 年,经过一系列奇特的事件后,英特尔推出了世界上第一款8位微处理器——8008。当时,英特尔主要是一家内存芯片供应商。8008是由计算机终端公司(CTC)委托研发,用于他们的新款Datapoint 2200可编程终端。但这款芯片交付延迟,且未达到CTC的期望。因此,英特尔为其添加了一些通用指令,并将芯片推向其他客户。

8008拥有七个8位寄存器:

“A”代表累加器(accumulator),它是算术和逻辑操作的隐式操作数和返回值。

你可能会想——天哪,七个寄存器真是个奇怪的数字——你想得没错!这些寄存器在指令中用三位编码,因此有八种组合。最后一个组合用于一个名为M的伪寄存器,M代表内存(注:这样相当于用3位编码即可找到寄存器和内存)。M指的是由寄存器H和L组合指向的内存位置。H代表内存地址的高位字节,L代表低位字节。这是8008中唯一可以引用内存的方式。

因此,A是一个累加器,H和L也用于内存寻址。而B、C、D、E则是完全通用的、可互换的寄存器。

8086 :A -> AX

在1979年,英特尔已成为一家微处理器公司,但他们的旗舰处理器iAPX 432遭遇延期。因此,作为权宜之计,他们推出了8086,这是一款从8080衍生而来的16位微处理器,而8080本身又是从8008衍生而来的。

为了利用现有的客户基础,英特尔使8086在软件上向下兼容至8008。一个简单的翻译程序可以将8008汇编代码翻译成8086汇编代码。为了实现这一点,8086的指令集体系结构必须与8008很好地映射,从而继承了许多设计决策。

8086拥有八个16位寄存器和八个8位寄存器,它们之间的重叠关系如下:

8086的指令中有一个位标志,用于指定寄存器的三位编码是指八个8位寄存器中的一个,还是八个16位寄存器中的一个。

从上图可以看出,前四个16位寄存器中的数据也可以通过八个8位寄存器之一来访问。

AX是一个16位累加器,而AH和AL可以被视为独立的8位寄存器,或者作为访问AX的高位字节和低位字节的方式。

AX中的“X”是一个占位符,代表H和L两者。(即对于累加器寄存器,“A”被保留,AL表示低8位(Low),AH表示高8位(High),而AX则表示完整的16位寄存器。

这在某种程度上类似于后来x86中的“x”,它用来指代8086、80186、80286等。

(注:设计师 Steve Morse 在本文最后给出了X的解释)

由于8008有七个8位寄存器,它们可以很好地映射到8086的八个寄存器,还多出一个寄存器。

M伪寄存器不再需要,因为8086支持多种内存寻址模式。因此,这释放了一个编码,用于额外的寄存器。

在下图中,你可以清楚地看到8008的寄存器是如何映射到8086的寄存器上的:

尽管许多算术和逻辑操作可以在这些寄存器中的任何一个上执行,但此时没有一个寄存器是真正通用的。每个寄存器都有一些特定指令,只对某个寄存器有效,而对其他寄存器无效。其助记符如下:BX是基址寄存器(Base Register),CX是计数寄存器(Count Register),DX是数据寄存器(Data Register),而AX仍是累加器(Accumulator)

新的SP是堆栈指针(Stack Pointer),BP是基址指针(Base Pointer),SI是源索引(Source Index),DI是目标索引(Destination Index)。但我们在这里不会详细讨论它们。

8086还引入了段寄存器(Segment Registers),但它们完全是另一回事。段式架构本身就值得单独讲述,因为它是保持与8080向后兼容的结果。

x86 :AX -> EAX

1985年,英特尔推出了80386,这是x86系列中第一款32位处理器。早期的一批处理器在某个32位操作中存在缺陷。这些处理器被标记为“仅限16位软件(16-BIT S/W ONLY)”并照常销售。

80386引入了许多新功能,但它(大部分)仍然与8086保持二进制兼容。

主要寄存器通过添加“E”前缀扩展到32位:

EAX代表扩展的AX(Extended AX)。而AX现在指的是EAX的下半部分,AH和AL继续分别指代AX的两个字节。

这就是EAX名字的由来。

但等等,故事还没完!

x86-64 :EAX -> RAX

2003年,AMD实际上接管了架构领导权,并推出了x86系列中第一款64位处理器。在传统模式(legacy mode)下,它向下兼容至8086。

八个主要寄存器被扩展到64位。

扩展的寄存器用前缀“R”替换了前缀“E”。因此,累加器现在被称为RAX:

AMD选择“R”是为了简化寄存器命名并保持一致性。他们引入了八个新的寄存器,命名为R8到R15。他们曾考虑将现有八个寄存器的64位扩展版命名为R0到R7,但注意到许多指令的助记符会引用寄存器字母,如A或B。因此,他们保留了原有名称,将前缀“E”替换为“R”。这也与新的R8–R15寄存器保持了一定的一致性。

因此,RAX中的“R”代表寄存器(Register),是统一命名的一种方式,使其与新的R8–R15寄存器更加一致。

新寄存器也有了它们的“窄”版本。以R15为例:

这就是x86累加器的简要历史!从8008的8位A,到8086的16位AX,再到80386的32位EAX,最后到64位的RAX。

更正

本文早先版本提到AX中的“X”代表“eXtended”(扩展)。一些读者指出这并不完全正确,“X”在某种意义上代表“pair”(一对)。我必须承认,与文章其他部分不同,我无法找到权威参考明确说明“X”的含义。于是,我决定联系8086的架构师Stephen Morse博士。

经他许可,我在此附上他的回复:

Vladimir,

你的问题确实在挑战我对40多年前决策的记忆。以下是我最好的回忆,不一定100%准确。

在8086之前,寄存器都用单个字母命名,例如A、B、C、D,每个都是8位寄存器。8086拥有16位寄存器,可以一次引用8位或整个16位。例如,我们可以引用A寄存器的高8位、低8位,或整个16位。前两者的命名被选为AL和AH,其中L/H分别表示低位或高位半部分。现在我们需要一个术语来表示完整的16位。于是选择了字母“X”。“X”只是一个任意字母,结合了L和H——有点像代数中用X表示未知数。对于“X”代表什么(如果有具体含义)并没有太多深思——它只是一个需要的字母,用来标识通用寄存器(AX、BX、CX、DX),以区别于指针和索引寄存器(SP、BP、SI、DI)以及段寄存器(CS、DS、ES、SS)。

——史蒂夫·摩斯

参考文献

《英特尔微处理器:8008到8086》,Stephen Morse著。

其他:X86的特殊寄存器

部分寄存器名称直接源于功能缩写,与技术迭代无关:

  • SP(Stack Pointer):始终指向栈顶,命名源自堆栈操作。
  • BP(Base Pointer):用于栈帧寻址,标识数据基址。
  • SI/DI(Source/Destination Index):在字符串操作中标记源/目标地址,名称直指其角色。
  • IP/EIP/RIP(Instruction Pointer):指向下一条指令地址,随位宽升级增加E/R前缀。

x86寄存器名称的演变遵循两条主线:

  1. 技术代际标识:通过X→E→R前缀链,标记处理器位宽升级,形成可追溯的技术谱系。
  2. 历史兼容性:旧名称作为新寄存器的子集保留,确保汇编代码跨代运行。

作者:Javen
链接:https://www.zhihu.com/question/351139937/answer/97785905488

CS: Code Segment
SS: Stack Segment
DS, ES, FS, GS: Data Segments (Data, E, F, G,有一说E来自Extra)
SP: Stack Pointer
BP: Base Pointer
SI: Source Index
DI: Destination Index
IP: Intstruction Pointer

链接:https://www.zhihu.com/question/351139937/answer/865616768

更多英文阅读:
The Art of Picking Intel Registers