Как просмотреть сборку за кодом с помощью Visual C ++?

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

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

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


person Community    schedule 19.06.2009    source источник
comment
Это называется листингом сборки в msvc, как уже упоминалось другими. Я создал простой плагин, добавляющий записи в контекстное меню редактора, чтобы автоматизировать эти утомительные шаги: marketplace. visualstudio.com/items?itemName=Trass3r.DevUtils   -  person Trass3r    schedule 31.01.2019


Ответы (10)


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

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

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

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

person inazaruk    schedule 19.06.2009
comment
Обратите внимание, что подход №2 не работает при компиляции статической библиотеки с включенной оптимизацией всей программы (по крайней мере, в VS2010). Что имеет смысл - компилятор еще не сгенерировал окончательный код. - person dhaffey; 26.03.2013
comment
В Visual Studio 2017 это называется Goto Disassembly. - person Matthias; 17.05.2017
comment
При подходе №2 как я могу увидеть сборку? - person user1507435; 22.02.2019
comment
Должен увидеть файл .asm в каталоге отладки, если вы использовали расположение по умолчанию. - person user3015682; 19.04.2020

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

person Vladimir Obrizan    schedule 20.06.2009
comment
Я заметил, что при дизассемблировании исполняемого файла Debug кажется, что код распаковывается во время работы, этого не происходит в версии Release. Также при открытии обоих с помощью PEiD только версия Debug показывает Microsoft Visual C ++ 8.0 [Debug]. - person jyz; 24.02.2013
comment
Это абсолютно верно. Но это вообще не отвечает на вопрос. - person imallett; 16.05.2015

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


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

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

person diapir    schedule 19.06.2009

Предыдущая версия этого ответа («взлом» для rextester.com) теперь в основном избыточна, поскольку http://gcc.godbolt.org/ предоставляет CL 19 RC для ARM, x86 и x86-64 (с учетом соглашения о вызовах Windows, в отличие от gcc, clang и icc на этом сайте).

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

Некоторое время CL была доступна на http://gcc.beta.godbolt.org/, но не на основном сайте, но теперь на обоих.


Чтобы получить вывод MSVC asm из онлайн-компилятора http://rextester.com/l/cpp_online_compiler_visual: добавьте /FAs в параметры командной строки. Пусть ваша программа найдет свой собственный путь, определит путь к .asm и сбросит его. Или запустить дизассемблер на .exe.

например http://rextester.com/OKI40941

#include <string>
#include <boost/filesystem.hpp>
#include <Windows.h>

using namespace std;

static string my_exe(void){
    char buf[MAX_PATH];
    DWORD tmp = GetModuleFileNameA( NULL, // self
                                  buf, MAX_PATH);
    return buf;
}

int main() {
    string dircmd = "dir ";
    boost::filesystem::path p( my_exe() );
    //boost::filesystem::path dir = p.parent_path();

    // transform c:\foo\bar\1234\a.exe 
    // into      c:\foo\bar\1234\1234.asm
    p.remove_filename();
    system ( (dircmd + p.string()).c_str() );

    auto subdir = p.end();      // pointing at one-past the end
    subdir--;                   // pointing at the last directory name
    p /= *subdir;               // append the last dir name as a filename
    p.replace_extension(".asm");
    system ( (string("type ") + p.string()).c_str() );
//    std::cout << "Hello, world!\n";
}

... code of functions you want to see the asm for goes here ...

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

IDK, почему, но cout << p.string() << endl показывает только базовое имя (то есть имя файла без каталогов), хотя печать его длины показывает, что это не просто голое имя. (Chromium48 в Ubuntu 15.10). Вероятно, в какой-то момент в cout или между стандартным выводом программы и веб-браузером есть некоторая обработка обратного слэша.

person Peter Cordes    schedule 09.02.2016
comment
@MichaelPetch: о, оказывается, это это то, что я пробовал. .c_str() печатает то, что похоже на указатель. Если вы перейдете по ссылке, вы увидите код для шестнадцатеричного дампа std::string (отключен с помощью #if 0). Оказывается, строка в порядке, но cout не получает ее в веб-браузер. Также нет никаких символов, отличных от ascii, только обратная косая черта. - person Peter Cordes; 10.02.2016
comment
Возможно, я что-то упускаю, но когда вы это сделали subdir--; p /= *subdir;, разве вы не уменьшили p до имени файла? Или, может быть, я неправильно понимаю, что вы пытаетесь напечатать. - person Michael Petch; 10.02.2016
comment
Думаю, я не совсем понимаю subdir--, за которым следует p /= *subdir, когда subdir изначально был p.end() - person Michael Petch; 10.02.2016
comment
@MichaelPetch: обновленные комментарии. Мне нужно было получить последний компонент каталога пути для использования в качестве имени файла. Это действительно работает, но мне потребовалось много времени, чтобы разобраться, потому что я думал, что GetModuleFileNameA просто возвращается a.exe. Только когда я сделал его шестнадцатеричный дамп и напечатал длину, я знал, что он работает, и я мог заставить программу манипулировать путем, я просто не мог распечатать путь - person Peter Cordes; 10.02.2016
comment
@MichaelPetch: Сначала я печатал его до каких-либо манипуляций. Но нет, я не отбрасываю ведущие компоненты. /= перегружен, чтобы добавить разделитель пути, а затем правую часть. Если я удалю те строки, которые вы предлагаете, это не сработает! Я преобразовываю c:\foo\bar\1234\a.exe в c:\foo\bar\1234\1234.asm, удаляя \a.exe, затем устанавливаю итератор на компоненты каталога пути, чтобы я мог добавить только 1234. - person Peter Cordes; 10.02.2016
comment
Да, похоже, это \\r (ну, \r, когда компилятор выводит ее) часть имени файла, которую он плохо переводил при рендеринге для веб-браузера. Использование p.generic_string() работает, но обратная косая черта является прямой. - person Michael Petch; 10.02.2016
comment
@MichaelPetch На самом деле это не кажется проблемой, поскольку Windows рассматривает любую косую черту как допустимый разделитель путей. - person Justin Time - Reinstate Monica; 09.10.2016

В Visual C ++ параметры проекта в разделе «Выходные файлы», как мне кажется, имеют возможность вывода списка ASM с исходным кодом. Таким образом, вы увидите исходный код C / C ++ и полученный ASM в одном файле.

person jcopenha    schedule 19.06.2009

Для MSVC вы можете использовать компоновщик.

link.exe / дамп / белье / disasm /out:foo.dis foo.dll

foo.pdb должен быть доступен для получения символов

person Steve Steiner    schedule 11.02.2012

.NET Reflector от Red Gate - отличный инструмент, который помог мне больше, чем несколько раз. Плюс этой утилиты, помимо простой демонстрации MSIL, заключается в том, что вы можете анализировать множество сторонних DLL, а Reflector позаботится о преобразовании MSIL в C # и VB.

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

person Dave L    schedule 20.06.2009
comment
Примечание: применимо только к управляемым сборкам, а не к разборке, как в ассемблере, asm. - person sean e; 20.06.2009
comment
Хороший момент, я прочитал это как две строки кода, одинаковые в сборке, а не две строки кода, одинаковые в сборке - person Dave L; 20.06.2009
comment
Он будет работать только с приложениями dotnet, а не с компоновщиком или компилятором Visual C ++. - person Sorry IwontTell; 14.05.2020

Если вы говорите об отладке, чтобы увидеть код сборки, самый простой способ - это Debug-> Windows-> Disassembly (или Alt-8). Это позволит вам войти в вызываемую функцию и остаться в разборке.

person Aabbee    schedule 29.01.2020

Использование Visual Studio 6.0

Нажмите на пункт меню Project

Нажмите на Настройки

Выбрать заголовок вкладки C / C ++

Изменить категорию на файлы списков

В разделе Тип файла списка измените поле со списком с Нет списка на Сборка с машинным кодом.

Файлы исходного кода сборки появятся в папке Release как файлы .cod.

person Tim Pearson    schedule 06.04.2021