GAS为下列指令提供了以下编码:
push rbp # 0x55
push rbx # 0x53
push r12 # 0x41 0x54
push r13 # 0x41 0x55来自AMD64规范 (第313页):
PUSH reg64 50 +rq将64位寄存器的上下文推送到堆栈上。
由于rbp和rbx的偏移量分别为5和3,所以前两种编码是有意义的。不过,我不明白最后两个编码是怎么回事。
据我所知,0x40-0x4f是REX前缀,0x41有REX.B位集(根据这个外部参考,这要么是对MSB的MODRM.rm或SIB.base的扩展)。规范提到,要访问所有16种GPRs,您需要使用REX,但还不清楚截止点在哪里。
从参考MODRM和SIB的文档来看,我不认为SIB是被使用的,因为它的目的是使用base+offset寄存器进行索引(不过老实说,我不能真正区分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)。如果忽略外部(非官方)参考中的所有表,REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5,这是push指令基0x50的第一个咬点。
所以,我想我已经倒过来了,但是我不明白我怎么会得到像0x41 0x54这样的编码。在AMD参考中,图1-10 (第54页)有一个脚注,如果是MODRM.mod = 01 or 10,那么字节“包括由指令移位字段指定的偏移量”。这也许会暗示我们为什么会有指令偏移量REX.R + MODRM.mod + MODRM.reg = 0b00101 = 5。但是,为什么MODRM.mod是指令偏移量的一部分?如果必须包括它,则采用此偏移形式的指令仅限于前缀0b01或0x10。不可能是对的,对吧?
tl;dr
push这样的指令是如何工作的?push rbp或push rbx那样为push rbp做0x50 + 12?)MODRM.mod包含在指令库的前缀中?(或者说这是完全正确的?)pop,这是一致的吗?(我怎么知道哪种指令支持这一点呢?它是否适用于具有表单XX +xx操作码的所有指令?)发布于 2019-02-05 00:56:16
这里显然没有ModRM字节,因为整个指令是一个字节。没有操作码字节就不能有ModRM。
push reg/pop reg短表单将3位寄存器代码嵌入到操作码字节中.这就是50 + rq的意思。(与push r/m64编码不同,它确实使用了ModRM;您可以用它对寄存器操作数进行编码,以使指令更长,但通常您只会将其用于push qword [rdi]或其他方面)。
它的格式与16 /32位相同,这就是为什么x86-64需要额外的位(来自REX前缀)来编码一个具有4位代码并设置了前导位的“新”/高级寄存器。
OSdev省略了这种情况,只提到了ModRM.rm和SIB.base。
Intel的第2卷手动PDF文档记录了编码:
E 227字节用于对寄存器操作数进行编码,而不使用modR/M字节。指令列出了操作码字节的对应十六进制值,该字节的低3位值为000b。在非64位模式下,从0到7的寄存器代码被添加到操作码字节的十六进制值中.在64位模式下,表示REX.b的4位字段和opcode2:0字段编码指令的寄存器操作数。“+ro”仅适用于64位模式。代码见表3-1。表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 for 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位模式。不过,他们确实收回了作为REX前缀的0x4? inc/dec reg操作码。
https://stackoverflow.com/questions/54519462
复制相似问题