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

117

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

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

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

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

Ответы:

149

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

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

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

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

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

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

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

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


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

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

диапир
источник
8

Более ранняя версия этого ответа («взлом» для 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это версия для DOS cat. Я не хотел включать больше кода, который усложнил бы поиск функций, для которых я хотел видеть asm. (Хотя использование зОго :: строки и счетчика подталкивания запуска для этих целей! Некоторый C-стиль строка манипуляции , что делает больше предположений о последовательности это обработки (и игнорирует макс длиной безопасности / распределение, используя большой буфер) в результате GetModuleFileNameAWould быть намного меньше общего машинного кода.)

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

Питер Кордес
источник
@MichaelPetch: ах, оказывается, что это то , что я пытался. .c_str()печатает то, что похоже на указатель. Если вы перейдете по ссылке, вы увидите код для шестнадцатеричного дампа a std::string(отключен с помощью #if 0). Оказывается, строка в порядке, но coutне получает ее в веб-браузер. Также нет никаких символов, отличных от ascii, только обратная косая черта.
Питер Кордес,
Возможно, мне что-то не хватает, но когда вы это subdir--; p /= *subdir;сделали, разве вы не уменьшили p до имени файла? Или, может быть, я неправильно понимаю, что вы пытаетесь напечатать.
Майкл Петч,
Думаю, я не совсем понимаю, за чем subdir--следовало, p /= *subdirкогда subdirбыло изначальноp.end()
Майкл Петч
@MichaelPetch: обновленные комментарии. Мне нужно было получить последний компонент каталога пути для использования в качестве имени файла. Это действительно работает, но мне потребовалось много времени, чтобы разобраться, потому что я думал, что GetModuleFileNameAтолько что вернулся a.exe. Только когда я сделал его шестнадцатеричный дамп и напечатал длину, я знал, что он работает, и я мог заставить программу манипулировать путем, я просто не мог распечатать путь
Питер Кордес
1
Да, похоже \\r(хорошо, \rкогда компилятор выводит) часть имени файла, которую он плохо переводил при рендеринге для веб-браузера. Использование p.generic_string()работает, но обратная косая черта является прямой.
Майкл Петч
5

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

jcopenha
источник
5

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

link.exe / дамп / льняные числа / disasm /out:foo.dis foo.dll

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

Стив Штайнер
источник
1

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

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

Дэйв Л.
источник
2
Примечание: применимо только к управляемым сборкам, а не к разборке, как в ассемблере, asm.
sean e
Хороший момент, я прочитал это как «две строки кода одинаковы в сборке» вместо «две строки кода одинаковы в сборке»
Дейв Л.
Он будет работать только с приложениями dotnet, а не с компоновщиком или компилятором Visual C ++.
Мухаммед Али
1

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

Aabbee
источник