如何使用Visual C ++查看代码背后的程序集?


116

我正在阅读另一个有关两行代码的效率的问题,OP表示他查看了代码后面的汇编,并且这两行在汇编中是相同的。除了题外话,我如何查看编译程序时创建的汇编代码。

我正在使用Microsoft的Visual C ++,但我也想知道是否可以查看用Visual Basic编写的代码背后的程序集。

那么,如何查看用高级语言(如C ++和Visual Basic)编写的程序背后的汇编代码?


正如其他人已经提到的,它在msvc中称为程序集列表。我创建了一个简单的插件,将条目添加到编辑器上下文菜单中以自动执行这些繁琐的步骤:marketplace.visualstudio.com/items?
itemName=Trass3r.DevUtils

Answers:


149

有几种方法:

  1. 您通常可以在Visual Studio中调试C ++时(也可以在Eclipse中)看到汇编代码。为此,在Visual Studio中,在有问题的代码上放置一个断点,并在调试器点击它时立即单击并找到“转到程序集”(或按CTRL + ALT + D)

  2. 第二种方法是在编译时生成程序集列表。为此,请转到项目设置-> C / C ++->输出文件-> ASM列表位置,然后填写文件名。还要选择“汇编输出”到“用源代码汇编”。

  3. 编译程序并使用任何第三方调试器。您可以为此使用OllyDbg或WinDbg。您也可以使用IDA(交互式反汇编程序)。但这是做到这一点的硬性方法。


5
请注意,方法2(在启用了整个程序优化的情况下编译静态库时不起作用)(至少在VS2010中)。这很有意义-编译器尚未生成最终代码。
dhaffey 2013年

3
在Visual Studio 2017中将其称为“ Goto Disassembly”(Goto反汇编)
Matthias,

使用方法2,如何查看装配体?
user1507435 '19

如果使用默认位置,则应在调试目录中看到一个.asm文件。
user3015682

28

附加说明:Debug汇编程序输出与Release 1的输出之间有很大差异。第一个很好的方法是学习编译器如何从C ++生成汇编代码。第二点对学习编译器如何优化各种C ++结构很有帮助。在这种情况下,从C ++到asm的转换并不明显。


我注意到,在反汇编Debug可执行文件时,它似乎在运行时会解压缩代码,而在Release版本上则不会发生。同样,当使用PEiD两者打开时,仅Debug版本显示“ Microsoft Visual C ++ 8.0 [Debug]”。
jyz

9
这是绝对正确的。但这根本无法回答问题。
imallett

25

为cl编译器指定/ FA开关。根据开关的值,仅集成汇编代码或高级代码和汇编代码。文件名将获得.asm文件扩展名。以下是受支持的值:


  • / FA汇编代码;.asm
  • / FAc机器和汇编代码;.cod
  • / FAs源代码和汇编代码;.asm
  • / FAcs机器,源代码和汇编代码;.cod


8

由于http://gcc.godbolt.org/为ARM,x86和x86-64(针对Windows调用约定)提供了CL 19 RC,因此该答案的较早版本(rextester.com的“ hack”)大部分是多余的。,与该网站上的gcc,clang和icc不同)。

Godbolt编译器资源管理器旨在很好地格式化编译器的asm输出格式,消除了指令的“噪音”,因此,我强烈建议使用它来查看带有args并返回值的简单函数的asm(因此它们不会优化掉)。

有一段时间,CL可以在http://gcc.beta.godbolt.org/上找到,但不能在主要站点上找到,但是现在两者都可以使用。


要从http://rextester.com/l/cpp_online_compiler_visual在线编译器获取MSVC asm输出,请执行以下操作:添加/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的功能变得更加困难。(虽然使用的std :: string和升压背道而驰的那些目标!某些C风格的字符串操作,使得关于它的处理(和字符串更多的假设通过对结果使用大缓存)忽略最大长度安全/配置GetModuleFileNameA会少得多的总机器代码。)

IDK为什么,但cout << p.string() << endl仅显示基本名称(即文件名,不包含目录),即使打印其长度显示它也不只是裸名。(在Ubuntu 15.10上为Chromium48)。在中的某个位置cout或程序的stdout与网络浏览器之间可能存在一些反斜杠转义处理。


@MichaelPetch:哦,原来那我尝试过的。 .c_str()打印看起来像指针的东西。如果您点击链接,则会看到将a十六进制转储的代码std::string(已禁用#if 0)。事实证明,该字符串很好,但cout没有将其发送到Web浏览器。也没有任何非ASCII字符,只是反斜杠。
彼得·科德斯

我可能会丢失一些东西,但是当您没有时,您subdir--; p /= *subdir;是否将p减小为仅文件名?也许我误会了您要打印的内容。
Michael Petch

我想我不太了解subdir--随后的p /= *subdir时间subdir是什么时间p.end()
Michael Petch

@MichaelPetch:更新的评论。我需要获取路径的最后一个目录组件以用作文件名。它确实有效,但是我花了很长时间才解决,因为我以为GetModuleFileNameA只是回来了a.exe。直到我将其十六进制转储并打印出我知道它正在工作的长度,然后我才可以让程序来操纵路径,我只是无法打印出路径
Peter Cordes

1
是的,似乎是文件名的一部分\\r\r当编译器输出时),在为Web浏览器渲染时,文件名翻译不佳。使用p.generic_string()Works,但反斜杠为正斜杠。
Michael Petch

5

在Visual C ++中,“我相信输出文件”下面的项目选项有一个选项,用于输出带有源代码的ASM清单。因此,您将在同一文件中看到C / C ++源代码和生成的ASM。


5

对于MSVC,您可以使用链接器。

link.exe /转储/行号/disasm/out:foo.dis foo.dll

foo.pdb需要可用于获取符号


1

Red Gate的.NET Reflector是一个非常出色的工具,已经帮助了我多次。除了可以轻松显示MSIL之外,此实用程序的优点还在于,您可以分析许多第三方DLL,并让Reflector负责将MSIL转换为C#和VB。

我不保证代码会像源代码一样清晰,但是遵循它不会有太多麻烦。


2
注意:仅适用于托管程序集,而不能像汇编程序asm中那样进行反汇编。
肖恩e

好点,我读它为“汇编中的两行代码是否相同”,而不是“汇编中的两行代码相同”
Dave L

它仅适用于dotnet应用程序,不适用于Visual C ++链接器或编译器。
穆罕默德·阿里

1

如果要谈论调试以查看汇编代码,最简单的方法是Debug-> Windows-> Disassembly(或Alt-8)。这将使您进入被调用的函数并停留在反汇编中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.