online emulador compiler code assembler asm assembly code-generation x86-64

assembly - emulador - ¿Por qué Visual Studio usa xchg axe, ax



c to asm (5)

Estaba revisando el programa de mi programa (porque se bloqueó) y noté un montón de

xchg ax, ax

Busqué en Google y descubrí que es esencialmente un nop, pero ¿por qué visual studio hace un xchg en lugar de un noop?

La aplicación es una aplicación C # .NET3.5 de 64 bits, compilada por Visual Studio


En realidad, xchg ax,ax es exactamente como MS desmonta "66 90". 66 es la anulación del tamaño del operando, por lo que supuestamente opera en ax lugar de eax . Sin embargo, la CPU todavía lo ejecuta como un nop. El prefijo 66 se usa aquí para hacer que la instrucción tenga dos bytes de tamaño, generalmente con fines de alineación.


En x86, la instrucción NOP es XCHG AX, AX

Las 2 instrucciones nemotécnicas se ensamblan con el mismo código de operación binario. (En realidad, supongo que un ensamblador podría usar cualquier xchg de un registro consigo mismo, pero AX o EAX es lo que típicamente se usa para el nop , hasta donde yo sé).

xchg ax, ax tiene las propiedades de cambiar ningún valor de registro y cambiar sin banderas (hey - ¡no es una operación!).

Editar (en respuesta a un comentario de Anon):

Ah, sí, ahora recuerdo que hay varias codificaciones para la instrucción xchg . Algunos toman un conjunto de bits mod / r / m (como muchas instrucciones de arquitectura Intel x86) que especifican una fuente y un destino. Esas codificaciones toman más de un byte. También hay una codificación especial que usa un solo byte e intercambia un registro de propósito general con (E)AX . Si el registro especificado también es (E)AX gallina tiene una instrucción NOP de un solo byte. también puede especificar que (E)AX se intercambie consigo mismo utilizando la variante más grande de la instrucción xchg .

Supongo que MSVC usa la versión de byte múltiple de xchg con (E)AX como fuente y destino cuando quiere masticar más de un byte para ninguna operación: toma el mismo número de ciclos que el byte xchg , pero usa más espacio. En el desmontaje, no verá decodificado byte xchg múltiple como NOP , incluso si el resultado es el mismo.

Específicamente, xchg eax, eax o nop podrían codificarse como 0x90 0x87 0xc0 o 0x87 0xc0 dependiendo de si desea utilizar hasta 1 o 2 bytes. El desensamblador de Visual Studio (y probablemente otros) decodificará el código de operación 0x90 como la instrucción NOP y decodificará el código de operación 0x87 0xc0 como xchg eax, eax .

Ha pasado un tiempo desde que hice el trabajo detallado del lenguaje ensamblador, así que es probable que me equivoque en al menos un cargo aquí ...


MSVC pone NOP en el código compilado para compilaciones de depuración, en general. Esto permite que Edit & Continue funcione.


No sé si tiene algo que ver con la pregunta, pero muchas funciones de Windows comienzan con MOV EDI, EDI. Eso también es un NOP de 2 bytes. Dos bytes de NOP son útiles para el código de hotpatch, porque puede reemplazarlo de manera segura con un JMP corto.

Referencia: http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214405.aspx


xchg ax,ax y nop son en realidad la misma instrucción, se asignan al mismo código de operación (0x90 iirc). xchg ax,ax bien, xchg ax,ax es un No-Op. ¿Por qué debería uno perder codificaciones de código de operación adicionales con instrucciones que no hacen nada?

Cuestionable es la razón por la que se ven impresos ambos mnemotécnicos. Supongo que es solo un error en el desmontaje, no hay diferencia binaria.