Windows ASM x64中的40h REX操作码的用途是什么?

Windows ASM x64中的40h REX操作码的用途是什么?,windows,64-bit,x86-64,disassembly,opcode,Windows,64 Bit,X86 64,Disassembly,Opcode,我一直在试图理解ASM x64指令的0x40REX操作码的用途。例如,在从Kernel32.dll开始的函数序言中: 正如您所看到的,他们使用推送rbx作为: 40 53 push rbx 但仅使用53h操作码(不带前缀)也会产生相同的结果: 根据,REX前缀的布局如下所示: 所以40h操作码似乎什么也没做。有人能解释一下它的用途吗?这个04xh字节(即040h,041h…04fh)实际上是REX字节。正如您在问题中列出的,下半字节中的每一位都有其含义。值040

我一直在试图理解ASM x64指令的
0x40
REX操作码的用途。例如,在从Kernel32.dll开始的函数序言中:

正如您所看到的,他们使用推送rbx作为:

40 53      push        rbx 
但仅使用
53h
操作码(不带前缀)也会产生相同的结果:

根据,REX前缀的布局如下所示:


所以
40h
操作码似乎什么也没做。有人能解释一下它的用途吗?

这个
04xh
字节(即
040h
041h
04fh
)实际上是REX字节。正如您在问题中列出的,下半字节中的每一位都有其含义。值
040h
表示
REX.W
REX.R
REX.X
REX.B
都是
0
。这意味着添加该字节不会对该指令做任何操作,因为您不会覆盖任何默认REX位,并且它不是以AH/BH/CH/DH作为操作数的8位指令


此外,
X
R
B
位都对应于一些操作数。如果指令不使用这些操作数,则相应的REX位将被忽略。

我将其称为伪REX前缀,因为它在推送或弹出之前不执行任何操作。我想知道这是否是允许的,你的经验表明这是允许的

它之所以存在,是因为微软的人显然生成了上述代码。我推测,对于额外的寄存器,它是需要的,所以它们总是生成它,并且在不需要它的时候,它们不会费心删除它。另一种可能性是,指令的加长对调度和/或对齐有微妙的影响,可以使代码更快。当然,这需要对特定处理器有详细的了解


我在一家研究机器代码的优化公司工作。伪前缀很有用,因为它们使代码更加统一;需要考虑的案例较少。然后作为最后一步,多余的前缀可以被删除。

是的,我知道。那么,为什么要像我在上面展示的第一个函数中那样使用它呢?或者,他们的编译器是否使用了
40h
操作码作为某种对齐
nop
类型的填充符?@HansPassant:Hah,很有趣。on hotpatching在函数开头解释了nop类型指令的用途。虽然在我的例子中,
4053 push rbx
指令不仅仅是一个哑弹,就像五个
nop
s或
mov edi一样,edi
是(在那篇文章中给出的)。它实际上是有目的的。它只比预期的长一个字节。我错过了什么吗?@c00000fd:是的,你错过了什么。Microsoft使用冗余REX前缀使指令变长,而不是使用单独的NOP指令。这使代码运行得更快。当您进行热补丁时,您可以使用
jmp
替换一些早期指令以生成新代码,然后可能跳回函数的其余部分。你用5倍单字节
nop
指令链接的那篇文章是个糟糕的计划;当您将其替换为
jmp
@Nathan时,可以在第二个
nop
执行:
0x40
对字节寄存器有影响:例如,需要对
mov al、sil
进行编码。(这就是为什么AH/BH/CH/DH不能在带有REX前缀的指令中进行编码,所以不能对
mov AH,sil
进行编码)但是是的,对于
push
和除8位操作数大小指令以外的任何操作码,
0x40
是冗余的。这里似乎有两个问题:1)它做什么。2) 为什么在那里?它所做的(根据我正在阅读的参考资料)什么都不是。那么,它为什么会在那里?我的第一个猜测和Nathan的一样:某种类型的对齐/填充。但我在代码中看不到任何可以从对齐中获益的东西。所以,这里有一个理论:通过kernel32.dll分页,有很多
nop
s。这就像有人试图在特定地址保存某些代码一样。所以,也许
rex-push-rbx
是在一些短1字节的代码上打补丁的?这很奇怪,
push-rbx
有64位操作数大小,所以如果它们要用rex前缀填充(不需要,因为
push
已经默认为64位操作数大小),它应该使用
rex.W=1
(0x48)。我想,如果您在Windows上的
kernel32.dll
中找到了这一点,那么所有现有的CPU都会安全地忽略
REX.W=0
。噢,NASM将推送r12编码为4154,即使用REX.W=0,B=1`。显然,我需要去更新我的答案,因为该站点的链接被破坏了。@duru,该链接现在是唯一的性能优势,在这种情况下,它是作为一个单独的long-
nop
指令的替代品,为热补丁提供一些可替换的内容,这将更加糟糕。看见使指令变长不会造成太大的伤害,但会增加I-cache的占用空间,并可能意味着更糟糕地打包到uop缓存线中。如果在32字节的机器代码块中,平均指令长度小于2,则一些填充可能是好的,但不在这里。我正在查看使用VS 2008 SP2生成的某个内容的反编译,它有14621个序言,以
40 53 48 83 EC
(对于除peter之外的ppl,
push rbx;sub rsp,x
)。尽管他们很乐意使用
445535657
。。。在我看来,你的答案是正确的。此外,只有约500个函数的序言以1字节指令开头,所有这些(快速示例)实际上都不是函数。函数总数约为110000,因此。。。是 啊对于逆向工程师来说,这无疑是一个奖励:)