为什么Visual Studio使用xchg ax,ax

Mal*_*ist 29 assembly code-generation x86-64

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

xchg    ax, ax
Run Code Online (Sandbox Code Playgroud)

我用谷歌搜索它,发现它本质上是一个小鸟,但为什么visual studio会做一个xchg而不是noop?

该应用程序是由Visual Studio编译的C#.NET3.5 64位应用程序

Mic*_*urr 37

在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使用xchgwith 的多字节版本(E)AX作为源和目标,当它想要在没有操作的情况下咀嚼多个字节时 - 它需要与单个字节相同的周期数xchg,但占用的空间更多.在反汇编中,即使结果相同,也不会将多字节xchg解码为a NOP.

具体xchg eax, eaxnop可以编码为操作码0x900x87 0xc0取决于您是否要使用1或2个字节.Visual Studio反汇编程序(可能还有其他程序)会将操作码解码0x90NOP指令,并将操作码解码0x87 0xc0xchg eax, eax.

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

  • x86对于特定的寄存器有很多"快捷方式" - "0x90"是"`XCHG`寄存器和`(E)AX`". (2认同)

Ale*_*ler 9

xchg ax,ax并且nop实际上是相同的指令,它们映射到相同的操作码(0x90 iirc).那没关系,xchg ax,ax No-Op.为什么要浪费额外的操作码编码和不做任何事情的指令?

质疑的是,为什么你看到印双方助记符.我想这只是你的反汇编中的一个缺陷,没有二元差异.


Igo*_*sky 7

实际上,xchg ax,ax正是MS如何拆解"66 90".66是操作数大小覆盖,所以它应该操作ax而不是eax.但是,CPU仍然将其作为nop执行.这里使用66前缀来使指令的大小为两个字节,通常用于对齐目的.


Ale*_*ski 5

通常,MSVC 会将 NOP 放入已编译的代码中以进行调试构建。这允许“编辑并继续”工作。