GAS为以下指令提供了以下编码:
push rbp # 0x55
push rbx # 0x53
push r12 # 0x41 0x54
push r13 # 0x41 0x55
来自AMD64 spec(第313页):
PUSH reg64 50 +rq
将64位寄存器的上下文推入堆栈。
由于rbp
和rbx
的偏移量分别为5和3,因此前两种编码是有意义的。不过,我不明白最后两种编码的含义。
我知道0x40-0x4f
是REX前缀,并且0x41
设置了REX.B
位(它是MODRM.rm
或{{1}的MSB的扩展名) },根据此external reference)。该规范提到要访问所有16个GPR,您都需要使用REX,但不清楚截止位置。
从咨询MODRM和SIB的文档开始,我不认为会使用SIB,因为它的目的是使用基址+偏移量寄存器进行索引(尽管老实说,我无法真正告诉您如何区分MODRM和SIB SIB仅给出了编码)。
所以,我怀疑这里正在使用MODRM。目前仅考虑SIB.base
(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
=偏移量12)。如果您忽略external (unofficial) reference,r12
中的所有表,这是推送指令库REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5
的第一个半字节。
因此,我想我已经将其倒退了,但是我不明白如何获得像0x50
这样的编码。在AMD reference中,图1-10(第54页)的脚注是,如果0x41 0x54
,则字节“包括由指令位移字段指定的偏移量”。这也许暗示了为什么我们有指令偏移量MODRM.mod = 01 or 10
。但是,为什么指令的REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5
部分偏移了?如果必须包含它,则采用此偏移量格式的指令仅限于前缀MODRM.mod
或0b01
。那不对吧?
tl; dr
0x10
之类的指令?push
或push r12
那样为push rbp
做0x50 + 12?)push rbx
? (或者这完全正确吗?)MODRM.mod
之类的类似指令是否一致? (而且我怎么知道哪些指令支持此操作?它对所有具有pop
形式的操作码的指令都起作用吗?)答案 0 :(得分:4)
这里显然没有ModRM字节,因为 entire 指令是一个字节。没有操作码字节就无法拥有ModRM。
push reg
/ pop reg
简短形式将 3位寄存器代码嵌入到操作码字节中。这就是50 + rq
的意思。 (与使用ModRM的FF /6
push r/m64
编码不同;您可以 对该寄存器进行编码,以使指令更长,但通常仅将其用于push qword [rdi]
等等。
与16/32位相同,这就是为什么x86-64需要一个额外的位(来自REX前缀)来编码具有4位代码的“新” /高位寄存器之一的原因设置了前导位。
OSdev忽略了这种情况,只提到了ModRM.rm
和SIB.base
。
3.1.1.1 Opcode Column in the Instruction Summary Table (Instructions without VEX Prefix)
...
+ rb , + rw , + rd , + ro -表示为操作码的低3位字节用于对寄存器操作数进行编码,而无需 modR / M字节。该指令列出了相应的十六进制值 低3位的操作码字节的字节为000b。在非64位模式下, 寄存器代码(从0到7)加到的十六进制值 操作码字节。 在64位模式下,指示REX.b的四位字段 并且opcode [2:0]字段对指令的寄存器操作数进行编码。 “ + ro”仅适用于64位模式。有关代码,请参见表3-1。
表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
有趣的事实:在50 + rd
中,他们实际上使用50 + ro
而不是PUSH r64
,与32位模式下的push r32
相同。 https://www.felixcloutier.com/x86/push。
对于类似pop这样的说明,这是否一致? (而且我怎么知道哪些指令支持此功能?它对所有操作码形式为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前缀。