首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PUSH的Intel REX编码

PUSH的Intel REX编码
EN

Stack Overflow用户
提问于 2019-02-04 15:35:59
回答 1查看 1.1K关注 0票数 6

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

代码语言:javascript
复制
push rbp    # 0x55
push rbx    # 0x53
push r12    # 0x41 0x54
push r13    # 0x41 0x55

来自AMD64规范 (第313页):

PUSH reg64 50 +rq将64位寄存器的上下文推送到堆栈上。

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

据我所知,0x40-0x4f是REX前缀,0x41REX.B位集(根据这个外部参考,这要么是对MSB的MODRM.rmSIB.base的扩展)。规范提到,要访问所有16种GPRs,您需要使用REX,但还不清楚截止点在哪里。

从参考MODRM和SIB的文档来看,我不认为SIB是被使用的,因为它的目的是使用base+offset寄存器进行索引(不过老实说,我不能真正区分MODRM和SIB,仅仅考虑到编码)。

所以我怀疑MODRM在这里被使用了。考虑到目前只考虑到push r12 (0x41 0x54) (并注意到r12抵消了12),我们有:

代码语言:javascript
复制
+----------------+--------------------+
| 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是指令偏移量的一部分?如果必须包括它,则采用此偏移形式的指令仅限于前缀0b010x10。不可能是对的,对吧?

tl;dr

  • REX编码对像push这样的指令是如何工作的?
  • 需要REX前缀的指令偏移截止值是多少?(是否有文件表明,我不能像push rbppush rbx那样为push rbp做0x50 + 12?)
  • 为什么MODRM.mod包含在指令库的前缀中?(或者说这是完全正确的?)
  • 对于类似的指令,比如pop,这是一致的吗?(我怎么知道哪种指令支持这一点呢?它是否适用于具有表单XX +xx操作码的所有指令?)
  • 这在官方手册中有什么记载?
  • 如何区分REX前缀后面是MODRM还是SIB字节?
  • 是否有更好的文档可以将这些过程按步骤列出,而不是让您从一个表跳到另一个表的几个页面?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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.rmSIB.base

Intel的第2卷手动PDF文档记录了编码:

3.1.1.1指令摘要表中的Opcode列(没有VEX前缀的指令)

  • ..。
  • +rb+rw+rd+ro -表示操作码的下3位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位模式)”列中摘录了相关行:

代码语言:javascript
复制
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 regmov reg,immxchg eax, r32 / xchg rax, r64都使用3个操作码位的相同编码来对寄存器进行编码。

如果我们能让这8位xchg操作码返回到更有用的东西(比如64位模式下的更紧凑的VEX或EVEX前缀),那就太好了,但是当AMD与AMD64合作时,这艘船航行了,主要是保持机器代码尽可能类似于32位模式。不过,他们确实收回了作为REX前缀的0x4? inc/dec reg操作码。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54519462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档