【问题标题】:How to know if a register is a "general purpose register"?如何知道寄存器是否是“通用寄存器”?
【发布时间】:2018-01-14 05:38:35
【问题描述】:

我试图了解一个寄存器必须具备哪些标准才能被称为“通用寄存器”。

我认为通用寄存器是可以用于任何事情(用于计算、将数据移入/移出等)的寄存器,并且是没有特殊用途的寄存器。

现在我读到ESP 寄存器是一个通用寄存器。我猜ESP寄存器可以用来做任何事情,但是ESP寄存器还有一个特殊用途,就是指向栈顶。

那么这是否意味着ESP 寄存器是一个特殊用途的寄存器?

【问题讨论】:

  • 不要对术语感到厌烦。它是不一致的,也不需要是一致的,文档的作者,也许还有其他一些人可以根据文档来决定这些术语的含义。它不必比这更准确。
  • general purpose in general 表示您可以将其用于一般说明。 x86 通用目的的概念有点奇怪,因为指令集不是以这种方式开始的,后来有点混乱,但如果你可以将寄存器编码成各种指令,如 add、sub、xor、mul 以及加载和存储以及其他类似的东西,那么它通常可以在整个指令集中使用。同样,如果由于使用了特定的寄存器而有没有对寄存器进行编码的指令,那么这是特殊用途。没有理由为什么一个寄存器不能两者兼而有之。
  • 如果我理解您的问题,ESP 只不过是 i386 和更高版本 32 位寄存器大小的 SP(堆栈指针)。有关 Assembly 的出色网络参考,请参阅 The Art of Assembly Language Programming。虽然它主要是为 8086 编写的,但所有原则都 100% 适用于当前的汇编编程。唯一的区别是 x86_64 的寄存器大小、调用约定和系统调用号。

标签: assembly x86 cpu-registers


【解决方案1】:

通用寄存器(GPR)一词与专用寄存器相对。后者不能在所有情况下都使用。

从历史上看,旧的 8086 架构在其名称中引入了这种差异,直到今天:

  • AX = A累加器寄存器:累加结果(**)
  • BX = Base register:特定指令的基本偏移量,例如XLAT
  • CX = Counter register:循环计数,例如JCXZ
  • DX = Data register:扩展数据范围,例如MUL 的结果在 DX:AX 中
  • SI = S来源索引:字符串指令的来源,例如LODSB
  • DI = Destination index:字符串指令的目的地,例如STOSB
  • SP = Stack 指针:指向堆栈的当前项
  • BP = Base指针:指向当前子程序的基址(栈帧)

(**) AX/AL 也是某种特殊用途的寄存器。许多指令具有 AX/AL 的特殊编码作为操作数,例如使用MOV 加载段寄存器。

其他特殊用途寄存器

  • 段寄存器(CS、DS、ES、SS)
  • 标志寄存器 (FLAGS) 和
  • 指令指针 (IP)

直到今天,这些限制中的一些限制在实模式中的 16 位指令的寻址模式中使用(参见Intel® 64 and IA-32 Architectures Software Developer’s Manual 第 2 卷,第 2.1.5 节,表 2-1。"带 ModR/M 字节的 16 位寻址形式")


随着 32 位架构 - IA-32 的引入,整数寄存器的用途得到了普遍化,并且(几乎)每个寄存器都可以用于各种用途(因此是通用的)。这也反映在指令的寻址模式编码中,请参阅英特尔手册第 2 卷,第 2.1.5 节,表 2.2。 (比较表 2.1 和表 2.2 以了解区别)

名称的前缀分别为 EREAXRAX,以及它们的指示用法的历史名称现在只是常规名称。

在许多新架构中,添加了新的专用寄存器。 英特尔手册,第 1 卷,第 3.7.2 节提供了完整的概述。

  • 32 位通用寄存器(EAX、EBX、ECX、EDX、ESI、EDI、ESP 或 EBP)
  • 16 位通用寄存器(AX、BX、CX、DX、SI、DI、SP 或 BP)
  • 8 位通用寄存器(AH、BH、CH、DH、AL、BL、CL 或 DL)
  • 段寄存器(CS、DS、SS、ES、FS 和 GS)
  • EFLAGS 寄存器
  • x87 FPU 寄存器(ST0 到 ST7、状态字、控制字、标签字、数据操作数指针和指令 指针)
  • MMX 寄存器(MM0 到 MM7)
  • XMM 寄存器(XMM0 到 XMM7)和 MXCSR 寄存器
  • 控制寄存器(CR0、CR2、CR3 和 CR4)和系统表指针寄存器(GDTR、LDTR、IDTR 和任务 注册)
  • 调试寄存器(DR0、DR1、DR2、DR3、DR6 和 DR7)
  • MSR 寄存器

通用寄存器是一种可以用于多个目的的寄存器。这些目的是

  • 价值
  • 寻址
  • 索引
  • (计数)
  • (基础)

段寄存器,例如,只能保存段值,但不能用于加法。 FPU 寄存器只能保存浮点数,不能用于寻址。

在 IA-32 中,ESP 寄存器更接近于成为 通用寄存器,因为它可以用于(几乎)所有上述目的:

  • 作为值:mov eax, esp
  • 在寻址中:mov eax, [esp+4],但 不是mov eax, [4+esp*2] 这样的(缩放)索引
  • 作为基础:mov eax, [esp + eax]
  • 作为计数:inc esp 在跳转有效之前

ESP 的唯一例外是 (缩放)索引 寻址无法编码。它只能用作基址寄存器,该基址寄存器使用 SIB 字节进行特殊编码(参见英特尔手册,第 2 卷,第 2.1.5 节,表 2.3 - 参见页脚)。

为了说明ESP和其他寄存器(例如ECX)在编码上的区别:

8b 01         mov eax, [ecx]   ; MOV + ModRM (normal)
8b 04 24      mov eax, [esp]   ; MOV + ModRM + SIB byte
8b 41 04      mov eax, [ecx+4] ; MOV + ModRM + disp8
8b 44 24 04   mov eax, [esp+4] ; MOV + ModRM + SIB + disp8

我想尽管有这个例外,ESP 仍然可以算作一个 GPR

【讨论】:

  • [eax + esp] 只能编码为 [esp + eax*1](以 EAX 作为索引)。问题不是缩放本身,而是 ESP 不能是索引,只能是基址寄存器。大多数汇编程序会为您处理这个问题,除非您强制其中一个或另一个成为索引。 [ESP] 作为基础总是需要一个 SIB 字节有点像 [EBP] 总是需要一个 disp8/disp32。
  • 为什么说“与8086相反”?所有寄存器都不太通用(因为缺少movzx/movsx、缺少2 操作数imul 等),并且16 位寻址模式受到更多限制。但是,如果您愿意,您仍然可以使用 SP 作为 dec sp / jnz 的循环计数器。 (如果您不需要堆栈)。或者使用它而不是 [si] 来循环使用 pop 而不是 lods 的数组,就像我在 32-bit extended-precision Fibonacci code-golf 中所做的那样
  • 有趣的是,在 IA-32 中,一些寄存器仍然隐式绑定到一些指令
  • @PeterCordes:我试图通过使用您的建议来改进答案。但是,我没有进行重大重组。
【解决方案2】:

每个 x86 中的通用寄存器也被某些指令隐式使用,因此也是一个专用寄存器。这只是每个寄存器的一个示例,但还有更多示例。
eax: mul
ebx: xlat
ecx: shl
edx: div
编辑:stos
esi:lods
ebp:离开
esp: ret

【讨论】:

  • 还有 r8-r15 我相信没有被任何指令隐式使用
  • ebx: cmpxchg8b 的一个仍然相关的用途。那么您的示例都是现代编译器仍在实际使用的所有指令。实际上,他们不使用lods,但他们确实使用movs。无论如何,这与您的观点无关,但有趣的是,即使在现代编译代码中,所有低 8 位寄存器都是特殊的。
猜你喜欢
  • 2012-07-22
  • 2023-03-07
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
相关资源
最近更新 更多