gpt4 book ai didi

assembly - PUSH 的 Intel REX 编码

转载 作者:行者123 更新时间:2023-12-03 06:35:38 29 4
gpt4 key购买 nike

GAS 为以下指令提供以下编码:

push rbp    # 0x55
push rbx # 0x53
push r12 # 0x41 0x54
push r13 # 0x41 0x55

来自AMD64 spec (第 313 页):

PUSH reg64 50 +rq  Push the contexts of a 64-bit register onto the stack.

由于 rbprbx 的偏移量分别为 5 和 3,因此前两种编码是有意义的。不过,我不明白最后两种编码是怎么回事。

据我所知,0x40-0x4f 是一个 REX 前缀,0x41 具有 REX.B 位集(它是对MODRM.rmSIB.base 的 MSB,根据此 external reference )。规范提到要访问所有 16 个 GPR,您需要使用 REX,但尚不清楚截止点在哪里。

通过查阅 MODRM 和 SIB 的文档,我认为没有使用 SIB,因为它的目的是使用基址+偏移寄存器进行索引(尽管说实话,我无法真正告诉你如何区分 MODRM 和SIB 仅给出编码)。

所以,我怀疑这里使用了 MODRM。目前仅考虑 push r12 (0x41 0x54)(并注意 r12 具有偏移量 12),我们有:

+----------------+--------------------+
| 0x41 | 0x54 |
+----------------+--------------------+
| REX | MODRM |
+--------+-------+-----+--------+-----+
| Prefix | WRXB | mod | reg | rm |
| 0100 | 0001 | 01 | 01 0 | 100 |
+--------+-------+-----+--------+-----+

REX.B + MODRM.rm = 0b1100 = 12 因此这表明这是源寄存器(r12 = 偏移量 12)。如果忽略 external (unofficial) reference 中的所有表,REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5,这是推送指令基0x50的第一个半字节。

所以,我想我已经向后工作了,但我不明白如何得到像 0x41 0x54 这样的编码。来自 AMD reference ,图 1-10(第 54 页)有一个脚注,如果 MODRM.mod = 01 或 10,则该字节“包括由指令位移字段指定的偏移量”。这也许暗示了为什么我们有指令偏移量REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5。但是,为什么 MODRM.mod 部分是指令偏移量呢?如果必须包含它,则采用此偏移形式的指令仅限于前缀 0b010x10。这不可能是正确的,对吧?

tl;博士

  • REX 编码实际上如何适用于 push 等指令?
  • 需要 REX 前缀的指令偏移截止是多少? (有记录表明我不能像对 push rbppush rbx 那样对 push r12 执行 0x50 + 12 吗?)<
  • 为什么指令库的前缀中包含MODRM.mod? (或者这是正确的吗?)
  • 这对于 pop 等类似指令是否一致? (我怎么知道哪些指令支持这个?它适用于所有具有 XX +xx 形式的操作码的指令吗?)
  • 官方手册中对此有何记录?
  • 如何区分 REX 前缀后面是 MODRM 还是 SIB 字节?
  • 是否有更好的文档可以分步骤列出这些流程,而不是让您在表格之间的多个页面之间跳转?

最佳答案

这里显然没有 ModRM 字节,因为整个指令都是一个字节。如果没有操作码字节,就不可能有 ModRM。

push reg/pop reg短格式将3位寄存器代码嵌入到操作码字节中。这就是50 + rq方法。 (与使用 ModRM 的 FF /6 push r/m64 编码不同;您可以用它来编码寄存器操作数以使指令更长,但通常您只会将其用于 push qword [rdi] 或其他东西)。

它与 16/32 位格式相同,这就是为什么 x86-64 需要一个额外的位(来自 REX 前缀)来编码具有 4 位代码的"new"/上位寄存器之一设置了前导位。

OSdev省略了这个案例,只提到了ModRM.rmSIB.base .

<小时/>

英特尔第 2 卷手册 PDF 记录了编码:

3.1.1.1 Opcode Column in the Instruction Summary Table (Instructions without VEX Prefix)

  • ...

  • +rb, +rw, +rd, +ro — Indicated the lower 3 bits of the opcode byte is used to encode the register operand without a modR/M byte. The instruction lists the corresponding hexadecimal value of the opcode byte with low 3 bits as 000b. In non-64-bit mode, a register code, from 0 through 7, is added to the hexadecimal value of the opcode byte. In 64-bit mode, indicates the four bit field of REX.b and opcode[2:0] field encodes the register operand of the instruction. “+ro” is applicable only in 64-bit mode. See Table 3-1 for the codes.

表 3-1 使用与 ModRM 和 SIB 中的寄存器编号相同的编码方案,这并不奇怪,但英特尔全力以赴,拥有所有操作数大小的所有整数寄存器的完整表。包括AH/BH/CH/DH,因为mov ah, 1可以使用 2 字节短格式。

我从“四字寄存器(仅限 64 位模式)”列中摘录了相关行:

From Intel's Table 3-1. Register Codes Associated With +rb, +rw, +rd, +ro
reg REX.B Reg Field
RBX None 3

RBP None 5

R12 Yes 4
R13 Yes 5

有趣的事实:在英特尔的手册中,他们实际上使用 50 + rd而不是50 + ro对于 PUSH r64 ,与 push r32 相同在 32 位模式下。 https://www.felixcloutier.com/x86/push .

<小时/>

Is this consistent for similar instructions like pop? (And how do I know which instructions support this? Does it work for all instructions that have opcodes of the form XX +xx?)

是的。 push/pop reg , mov reg,imm ,和xchg eax, r32/xchg rax, r64全部使用相同的编码,具有 3 个操作码位来对寄存器进行编码。

如果我们能拥有这 8 个就好了 xchg操作码返回一些更有用的东西(比如 64 位模式下更紧凑的 VEX 或 EVEX 前缀),但是当 AMD 对 AMD64 采取保守态度时,这艘船航行了,主要保持机器代码尽可能与 32 位模式相似。他们确实收回了0x4? inc/dec reg不过,操作码用作 REX 前缀。

关于assembly - PUSH 的 Intel REX 编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54519462/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com