我正在查看程序的解散(因为它崩溃了),并注意到很多
xchg ax, ax
我用Google搜索并发现它基本上是一个小鸟,但为什么visual studio会用xchg而不是noop?
该应用程序是一个C#.NET3.5 64位应用程序,由visual studio
编译答案 0 :(得分:36)
在x86上,NOP
指令是 XCHG AX, AX
2个助记符指令汇编为相同的二进制操作码。 (实际上,我认为汇编程序可以使用任何 xchg
个寄存器,但AX
或EAX
通常用于nop
。我知道。
xchg ax, ax
具有更改无寄存器值和不更改标志的属性(嘿 - 这是一个没有操作!)。
修改(响应Anon的评论):
哦对了 - 现在我记得xchg
指令有几种编码方式。有些采用mod / r / m位(如许多Intel x86架构指令)来指定源和目标。这些编码需要多个字节。还有一种特殊编码,它使用单个字节并与(E)AX
交换通用寄存器。如果指定的寄存器也是(E)AX
,那么你有一个单字节的NOP指令。您还可以使用(E)AX
指令的较大变体指定xchg
与自身交换。
我猜测MSVC使用带有xchg
的{{1}}的多字节版本作为源和目标,当它想要在没有操作的情况下咀嚼多个字节时 - 它需要相同的数字循环作为单字节(E)AX
,但使用更多空间。在反汇编中,即使结果相同,您也不会将多字节xchg
解码为xchg
。
具体而言,NOP
或xchg eax, eax
可以编码为操作码nop
或0x90
,具体取决于您是否要使用1或2个字节。 Visual Studio反汇编程序(可能还有其他代码)会将操作码0x87 0xc0
解码为0x90
指令,并将操作码NOP
解码为0x87 0xc0
。
自从我完成了详细的汇编语言工作以来已经有一段时间了,所以我在这里至少有一次错误的机会是错的......
答案 1 :(得分:8)
xchg ax,ax
和nop
实际上是相同的指令,它们映射到相同的操作码(0x90 iirc)。没关系,xchg ax,ax
是No-Op。为什么要浪费额外的操作码编码和不做任何操作的说明?
可疑为什么你看到两个助记符都打印出来了。我想这只是你的反汇编中的一个缺陷,没有二元差异。
答案 2 :(得分:7)
实际上,xchg ax,ax
就是MS如何拆解“66 90”。 66是操作数大小覆盖,因此它应该在ax
而不是eax
上运行。但是,CPU仍然将其作为nop执行。这里使用66前缀来使指令大小为两个字节,通常用于对齐目的。
答案 3 :(得分:4)
MSVC通常将NOP放在编译代码中以进行调试构建。这允许Edit&继续工作。
答案 4 :(得分:2)
我不知道它是否与问题有关,但很多Windows功能都以MOV EDI,EDI开头。这也是一个2字节的NOP。两个字节的NOP对于hotpatch代码很有用,因为你可以用一个简短的JMP安全地替换它。
参考:http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214405.aspx
答案 5 :(得分:1)
真正的问题是;为什么反汇编程序选择将其显示为xchg ax,ax
而不显示为nop
?
我怀疑这是来自32位或64位代码,并且(假设反汇编程序显示xchg ax,ax
而不显示xchg eax,eax
)有一个操作数大小覆盖前缀旨在使{{ 1}}稍大一些(以较少的指令实现一定的填充量);并且前缀的存在使反汇编程序感到困惑,导致产生nop
(而不是xchg ax,ax
或nop
)。