Почему Visual Studio использует xchg ax, ax - PullRequest
28 голосов
/ 26 января 2010

Я просматривал разборку моей программы (потому что она вылетала) и заметил много

xchg    ax, ax

Я прогуглил это и обнаружил, что это по сути nop, но почему visual studio делает xchg вместо noop?

Приложение представляет собой 64-разрядное приложение на C # .NET3.5, скомпилированное Visual Studio

Ответы [ 6 ]

36 голосов
/ 26 января 2010

На x86 инструкция NOP равна XCHG AX, AX

2 мнемонические инструкции собираются в один и тот же двоичный код операции. (На самом деле, я полагаю, что ассемблер мог бы использовать любой xchg регистра с самим собой, но, насколько я знаю, AX или EAX - это то, что обычно используется для nop.

xchg ax, ax обладает свойствами изменения значений без регистров и без флагов (эй, это не операция!).


Редактировать (в ответ на комментарий Анона.):

Ах да, теперь я помню, что есть несколько кодировок для инструкции xchg. Некоторые принимают набор битов mod / r / m (как и многие инструкции по архитектуре Intel x86), которые указывают источник и назначение. Эти кодировки занимают более одного байта. Также есть специальная кодировка, которая использует один байт и заменяет регистр общего назначения на (E)AX. Если указанный регистр также (E)AX, то у вас есть однобайтовая инструкция NOP. Вы также можете указать, что (E)AX будет заменен на себя, используя больший вариант инструкции xchg.

Я предполагаю, что MSVC использует многобайтовую версию xchg с (E)AX в качестве источника и получателя, когда он хочет перебрать более одного байта без каких-либо операций - он занимает то же количество циклов, что и один байт xchg, но занимает больше места. В разборке вы не увидите многобайтовый xchg, декодированный как NOP, даже если результат тот же.

В частности, xchg eax, eax или nop могут быть закодированы как коды операций 0x90 или 0x87 0xc0 в зависимости от того, хотите ли вы использовать 1 или 2 байта. Дизассемблер Visual Studio (и, возможно, другие) декодирует код операции 0x90 как инструкцию NOP и декодирует код операции 0x87 0xc0 как xchg eax, eax.

Прошло много времени с тех пор, как я провел детальную работу на ассемблере, поэтому есть вероятность, что я ошибаюсь хотя бы в одном подсчете здесь ...

8 голосов
/ 26 января 2010

xchg ax,ax и nop фактически являются одной и той же инструкцией, они отображаются на один и тот же код операции (0x90 iirc). Это нормально, xchg ax,ax - это No-Op. Зачем тратить лишние коды операций с инструкциями, которые ничего не делают?

Сомнительно, что почему вы видите обе мнемоники напечатанными. Я думаю, что это просто недостаток в вашей разборке, нет никакой двоичной разницы.

7 голосов
/ 09 января 2012

На самом деле, xchg ax,ax - это то, как MS разбирает «66 90». 66 - это переопределение размера операнда, поэтому он предположительно работает на ax вместо eax. Тем не менее, процессор все еще выполняет его как nop. Префикс 66 используется здесь, чтобы сделать инструкцию размером в два байта, обычно для выравнивания.

4 голосов
/ 26 января 2010

MSVC обычно помещает NOP в скомпилированный код для отладочных сборок. Это позволяет редактировать и продолжить работу.

2 голосов
/ 12 мая 2015

Не знаю, связано ли это с вопросом, но многие функции Windows начинаются с MOV EDI, EDI. Это также 2-байтовый NOP. Два байта NOP полезны для горячего исправления кода, потому что вы можете смело заменить его коротким JMP.

Ссылка: http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214405.aspx

1 голос
/ 08 февраля 2019

Настоящий вопрос здесь; почему дизассемблер решил отображать его как xchg ax,ax, а не nop?

Я подозреваю, что это из 32-битного или 64-битного кода и (учитывая, что дизассемблер отображал xchg ax,ax, а не xchg eax,eax), что есть префикс переопределения размера операнда, предназначенный для увеличения nop немного ( добиться определенного количества отступов с меньшим количеством инструкций); и наличие префиксов сбило с толку дизассемблера, в результате чего xchg ax,ax (а не nop или o16 nop).

...