为什么Visual Studio使用xchg ax,ax

时间:2010-01-25 22:10:47

标签: assembly code-generation x86-64

我正在查看程序的解散(因为它崩溃了),并注意到很多

xchg    ax, ax

我用Google搜索并发现它基本上是一个小鸟,但为什么visual studio会用xchg而不是noop?

该应用程序是一个C#.NET3.5 64位应用程序,由visual studio

编译

6 个答案:

答案 0 :(得分:36)

在x86上,NOP指令 XCHG AX, AX

2个助记符指令汇编为相同的二进制操作码。 (实际上,我认为汇编程序可以使用任何xchg个寄存器,但AXEAX通常用于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

具体而言,NOPxchg eax, eax可以编码为操作码nop0x90,具体取决于您是否要使用1或2个字节。 Visual Studio反汇编程序(可能还有其他代码)会将操作码0x87 0xc0解码为0x90指令,并将操作码NOP解码为0x87 0xc0

自从我完成了详细的汇编语言工作以来已经有一段时间了,所以我在这里至少有一次错误的机会是错的......

答案 1 :(得分:8)

xchg ax,axnop实际上是相同的指令,它们映射到相同的操作码(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,axnop)。