GAS为以下说明提供了以下编码:
push rbp # 0x55
push rbx # 0x53
push r12 # 0x41 0x54
push r13 # 0x41 0x55
从AMD64 spec(页313):
由于
rbp
和rbx
的偏移量分别为5和3,因此前两种编码是有意义的。我不明白最后两种编码的情况。我知道
0x40-0x4f
是REX前缀,并且0x41
设置了REX.B
位(根据此external reference,它是MODRM.rm
或SIB.base
的MSB的扩展)。该规范提到要访问所有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 or 10
,则字节“包括由指令置换字段指定的偏移量”。这也许暗示了我们为什么要偏移指令REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5
。但是,为什么MODRM.mod
是指令偏移量的一部分呢?如果必须包含它,则采用此偏移量格式的指令仅限于前缀0b01
或0x10
。那是不对的,对不对?tl; dr
push
之类的指令? push r12
或push rbp
那样为push rbx
做0x50 + 12?)MODRM.mod
? (或者这完全正确吗?)pop
的类似指令是否一致? (而且我怎么知道哪些指令支持此功能?它对所有操作码形式为XX +xx
的指令都起作用吗?)最佳答案
显然这里没有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.rm
和SIB.base
。
英特尔第2卷手册PDF记录了以下编码:
毫无疑问,表3-1使用与ModRM和SIB中的寄存器编号相同的编码方案,但是Intel竭尽全力,并针对所有操作数大小,提供了所有整数寄存器的完整表。包括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
有趣的事实:在Intel手册中,他们实际上使用
50 + rd
而不是50 + ro
来表示PUSH r64
,与在32位模式下使用push r32
一样。 https://www.felixcloutier.com/x86/push。是的。
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的英特尔REX编码,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54519462/