Как посмотреть ассемблерный код в visual studio

Обновлено: 07.07.2024

Я читал еще один вопрос, касающийся эффективности двух строк кода, и OP сказал, что он посмотрел на сборку за кодом, и обе линии были идентичны в сборке. Отвлечение в сторону, как я мог просмотреть код сборки, созданный при компиляции программы.

Я использую Microsoft Visual С++, но мне также хотелось бы узнать, можно ли просмотреть сборку за кодом, написанным на Visual Basic.

Итак, как мне просмотреть код сборки за программой, написанной на языках более высокого уровня, таких как С++ и Visual Basic?

Существует несколько подходов:

Обычно вы можете увидеть код сборки во время отладки С++ в visual studio (и затмение тоже). Для этого в Visual Studio поставьте точку останова на код, о котором идет речь, и когда отладчик ударит его по щелчку и найдите "Go To Assembly" (или нажмите CTRL + ALT + D)

Скомпилируйте программу и используйте сторонний отладчик. Вы можете использовать OllyDbg или WinDbg для этого. Также вы можете использовать IDA (интерактивный дизассемблер). Но это хардкорный способ сделать это.

Дополнительное примечание: существует большая разница между выходом ассемблера Debug и Release one. Первый из них хорош, чтобы узнать, как компилятор создает код ассемблера с С++. Во-вторых, хорошо узнать, как компилятор оптимизирует различные конструкции С++. В этом случае некоторые преобразования С++-to-asm не очевидны.

Укажите ключ /FA для компилятора cl. В зависимости от значения коммутатора интегрируется только код сборки или код высокого уровня и код сборки. Имя файла получает расширение .asm файла. Вот поддерживаемые значения:

  • /код сборки FA;.asm
  • /FAc Машина и код сборки;.COD
  • /FAs Код источника и сборки;.asm
  • /FAcs Машина, источник и код сборки;.COD

Самый простой способ - запустить отладчик и проверить окно разборки.

Исследователь компилятора Godbolt разработан для удобного форматирования компилятора asm output, устраняя "шум" директив, поэтому я настоятельно рекомендую использовать его для просмотра asm для простых функций, которые принимают аргументы и возвращают значение (поэтому они выиграли 't быть оптимизированным прочь).

type - это версия DOS cat . Я не хотел включать больше кода, который затруднял бы поиск функций, которые я хотел увидеть для asm. (Хотя использование std::string и ускорение запуска счетчика для этих целей! Некоторые C-стиль строки манипуляции, которая делает больше предположений о обрабатываемой им строке (и игнорирует безопасность/распределение максимальной длины с помощью большого буфера) по результату GetModuleFileNameA будет намного меньше всего машинного кода.)

Многие из нас изучали ассемблер в университете, но почти всегда это ограничивалось простыми алгоритмами под DOS. При разработке программ для Windows может возникнуть необходимость написать часть кода на ассемблер, в этой статье я хочу рассказать вам, как использовать ассемблер в ваших программах под Visual Studio 2005.

image

Создание проекта

В статье мы рассмотрим как вызывать ассемблер из С++ кода и обратно, передавать данные, а также использовать отладчик встроенный в Visual Studio 2005 для отладки кода на ассемблер.

Для начала нам нужно создать проект. Включаем Visual Studio, выбираем File > New > Project. В Visual Studio нет языка ассемблер в окне выбора типа проекта, поэтому создаем С++ Win32 проект. В окне настроек нового проекта выбираем «Empty Project».

image

По умолчанию Visual Studio не распознает файлы с кодом на ассемблер. Для того чтобы включить поддержку ассемблер нам необходимо настроить в проекте условия сборки указав какой программой необходимо компилировать файлы *.asm. Для этого выбираем пункт меню «Custom Build Rules. ».

image

В открывшемся окне мы можем указать специальные правила компиляции для различных файлов, Visual Studio 2005 уже имеет готовое правило для файлов *.asm, нам необходимо лишь включить его, установив напротив правила «Microsoft Macro Assembler» галочку.

image

Добавление исходного кода

Перейдем к написанию исходного кода нашего проекта. Начнем с добавления исходного кода на c++. Добавим новый файл в папку Source Files. В качестве Template выбираем C++ File и вводим желаемое имя файла, например main.cpp. Напишем функцию, которая будет считывать имя введенное пользователем, оформив это в виде функции readName() которая будет возвращать ссылку на считанное имя. Мы получим примерно следующее содержимое файла:

Теперь, когда мы знаем имя пользователя мы можем вывести приветствие, его будет выводить функция sayHello() которую мы напишем на ассемблер, чтобы использовать эту функцию сначала мы должны указать что она будет определена в другом файле, для этого добавим блок к main.cpp:

Этот блок говорит компилятору, что функция sayHello() будет объявлена в другом файле и будет иметь правила вызова «C». Компилятор C++ искажает имена функций так, что указание правил вызова обязательно. Кроме того мы хотим использовать функцию readName() из функции sayHello(), для этого необходимо добавить extern «C» перед определением функции readName(), это позволит вызывать эту функцию из других файлов используя правила вызова «C».

Пришло время добавить код на ассемблер, для этого добавим в Source Folder новый файл. Выбираем тип Text File (.txt) и в поле название заменяем .txt на .asm, назовем наш файл hello.asm. Объявим функцию sayHello() и укажем внешние функции, которые мы хотим использовать. Получим следующий код:

Теперь мы можем запустить проект, для этого просто выбираем Debug > Start Without Debugging или нажимаем комбинацию Ctrl-F5. Если все сделано верно, вы увидите окно программы:

image

Немного усложним задачу, попробуем написать на ассемблер функцию принимающую параметр и возвращающую значение. Для примера напишем функцию calcSumm() которая будет принимать целое число и возвращать сумму его цифр. Изменим наш код на С++ добавив в него информацию о функции calcSumm, ввод числа и собственно вызов функции. Добавим функцию в файл hello.asm, возвращаемое значение помещается в eax, параметры объявляются после ключевого слова PROC. Все параметры можно использовать в коде процедуры, они автоматически извлекутся из стека. Также в процедурах можно использовать локальные переменные. Вы не можете использовать эти переменные вне процедуры. Они сохранены в стеке и удаляются при возврате из процедуры:

Запустив проект мы увидим следующий результат выполнения:

image

Отладка

Конечно в данной задаче нет ничего сложного и она вовсе не требует использования ассемблер. Более интересным будет рассмотреть, а что же нам дает Visual Studio для разработки на ассемблер. Попробуем включить режим отладки и установим точку остановки в hello.asm, запустим проект, мы увидим следующее:

image

Окно Disassembly (Debug > Windows > Disassembly) показываем команды ассемблер для данного объектного файла. Код который мы написали на С++ показывается черным цветом. Disassembled code показывается серым после соответствующего ему кода на C++/ассемблер. Окно Disassembly позволяет отлаживать код и осуществлять stepping по нему.

Окно регистров (Debug > Windows > Registers) позволяет посмотреть значение регистров.

Окно памяти (Debug > Windows > Memory) позволяет посмотреть дамп памяти, слева мы видим шестнадцатеричные адрес, справа шеснадцатеричные значения соответствующих ячеек памяти, можно перемещаться, вводя адрес в соответствующее поле в верху окна.

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

Я использую Microsoft Visual C ++, но мне также хотелось бы знать, можно ли просмотреть сборку кода, написанного на Visual Basic.

Итак, как мне просмотреть ассемблерный код программы, написанной на языках более высокого уровня, таких как C ++ и Visual Basic?

Есть несколько подходов:

Обычно вы можете увидеть код сборки при отладке C ++ в Visual Studio (и в Eclipse тоже). Для этого в Visual Studio поставьте точку останова на рассматриваемый код, и когда отладчик попадает в нее, щелкните правой кнопкой мыши и найдите «Перейти к сборке» (или нажмите CTRL + ALT + D).

Второй подход - генерировать листинги сборки во время компиляции. Для этого перейдите в настройки проекта -> C / C ++ -> Выходные файлы -> Расположение списка ASM и введите имя файла. Также выберите «Вывод сборки» на «Сборка с исходным кодом».

Скомпилируйте программу и используйте любой сторонний отладчик. Для этого вы можете использовать OllyDbg или WinDbg. Также вы можете использовать IDA (интерактивный дизассемблер). Но это хардкорный способ сделать это.

Обратите внимание, что подход №2 не работает при компиляции статической библиотеки с включенной оптимизацией всей программы (по крайней мере, в VS2010). Что имеет смысл - компилятор еще не сгенерировал окончательный код. В Visual Studio 2017 это называется «Goto Disassembly» Должен увидеть файл .asm в каталоге отладки, если вы использовали расположение по умолчанию.

Дополнительное примечание: существует большая разница между выводом Debug ассемблера и первым выпуском. Первый полезен, чтобы узнать, как компилятор создает код ассемблера из C ++. Второй полезен, чтобы узнать, как компилятор оптимизирует различные конструкции C ++. В этом случае некоторые преобразования C ++ в asm не очевидны.

Я заметил, что при дизассемблировании исполняемого файла Debug кажется, что код распаковывается во время работы, этого не происходит в версии Release. Также при открытии обоих с помощью PEiD только версия отладки показывает «Microsoft Visual C ++ 8.0 [Debug]». Это абсолютно верно. Но это вообще не отвечает на вопрос.

Укажите переключатель / FA для компилятора cl. В зависимости от значения переключателя интегрируется либо только код сборки, либо код высокого уровня и код сборки. Имя файла получает расширение .asm. Вот поддерживаемые значения:

  • / FA Код сборки; .как м
  • / FAc Машинно-сборочный код; .COD
  • / FAs Исходный и ассемблерный код; .как м
  • / FAcs Машинный код, исходный код и ассемблерный код; .COD

Самый простой способ - запустить отладчик и проверить окно разборки .

Обозреватель компилятора Godbolt разработан для красивого форматирования вывода asm компилятора, устранения "шума" директив, поэтому я настоятельно рекомендую использовать его для просмотра asm для простых функций, которые принимают аргументы и возвращают значение (чтобы они не были оптимизирован прочь).

type это версия для DOS cat . Я не хотел включать больше кода, который усложнил бы поиск функций, для которых я хотел видеть asm. (Хотя использование зОго :: строки и счетчика подталкивания запуска для этих целей! Некоторый C-стиль строка манипуляции , что делает больше предположений о последовательности это обработки (и игнорирует макс длиной безопасности / распределение, используя большой буфер) в результате GetModuleFileNameA Would быть намного меньше общего машинного кода.)

[b]Предисловие[/b]

Началось все с прочтения мной публикации «Ассемблер для Windows используя Visual Studio» (отсюда и почти идентичный код). Там рассмотрено использование Visual Studio 2005, а для 2013-й студии процесс похожий, но есть несколько отличий, которые заставят неподготовленного пользователя долго искать решения всех проблем со сборкой.

[b]Содержание[/b]

  1. TL;DR
  2. Создание проекта
  3. Настройка подсветки синтаксиса
  4. Тонкости вызова методов между С++ и Asm
  5. Приложение

Для тех, у кого совсем нет времени на прочтение: в конце статьи (в приложении) есть ссылка на готовый шаблон проекта и на аддон для подсветки синтаксиса.

[b]Создание проекта[/b]

Иллюстрированная версияВключаем Visual Studio, выбираем File -> New -> Project. :


Выбираем шаблон Win32 Console Application, кликаем ОК:



Ставим галочку напротив Empty project и жмем Finish:


Создаем исходники. Для этого делаем правый клик на Source Files, выбираем Add -> New Item. :


Выбираем C++ File и жмем Add:


Аналогично, создаем *.asm файл (просто меняем расширение в поле Name):


Важно: имена файлов должны быть разными (не учитывая расширение), иначе при создании файлов *.obj возникнет проблема перезаписи одного обьектного файла другим.

Теперь настройки. Делаем правый клик на проекте, выбираем Build Dependencies -> Build Customizations.


Ставим галочку напротив masm и жмем ОК:


Делаем правый клик на файле *.asm, выбираем Properties. :


В поле Item Type выбираем Microsoft Macro Assembler и жмем ОК:


Выбираем Project -> Properties. :



Выбираем Configuration Properties -> Linker -> Advanced. В поле Image Has Safe Exception Handlers выбираем значение No. Жмем ОК:


На этом этапе проект можно считать созданным. Написание кода рассмотрено в секции Тонкости вызова методов между С++ и Asm.

Только текстВключаем Visual Studio, выбираем File -> New -> Project. .

Выбираем шаблон Win32 Console Application, кликаем ОК.

Ставим галочку напротив Empty project и жмем Finish.

Создаем исходники. Для этого делаем правый клик на Source Files, выбираем Add -> New Item. .

Выбираем C++ File и жмем Add.

Аналогично, создаем *.asm файл (просто меняем расширение в поле Name).

Важно: имена файлов должны быть разными(не учитывая расширение), иначе при создании файлов *.obj возникнет проблема перезаписи одного объектного файла другим.

Теперь настройки. Делаем правый клик на проекте, выбираем Build Dependencies -> Build Customizations.

Ставим галочку напротив masm и жмем ОК.

Делаем правый клик на файле *.asm, выбираем Properties.

В поле Item Type выбираем Microsoft Macro Assembler и жмем ОК.

Выбираем Project -> Properties.

Выбираем Configuration Properties -> Linker -> Advanced. В поле Image Has Safe Exception Handlers выбираем значение No. Жмем ОК.

На этом этапе проект можно считать созданным. Написание кода рассмотрено в секции Тонкости вызова методов между С++ и Asm.

[b]Настройка подсветки синтаксиса[/b]

[b]Тонкости вызова методов между С++ и Asm[/b]

Для того, чтоб избежать ошибок компиляции и/или связывания нужно помнить следующее:

    Если надо вызывать из ассемблера библиотечные методы, достаточно в начале секции кода указать, какие именно методы мы собираемся использовать.

Далее можно просто использовать call:

Соответственно, в *.asm файле:

EXTRN readName : proc ;and void* readName()
и

call readName ;eax = readName()

Данный прототип соответствует такому объявлению Asm-метода:

call readName ;eax = readName()
lea ebx, helloFormat ;ebx = &helloFormat

;printf(ebx,eax)
push eax
push ebx
call printf
add esp, 8 ;pop x2

Собственно, полный исходный код примера:

call readName; eax = readName()
lea ebx, helloFormat; ebx = &helloFormat

;printf(ebx,eax)
push eax
push ebx
call printf
add esp, 8;pop x2

Читайте также: