如何使用 VisualC + + 查看代码后面的程序集?

我当时正在读另一个关于两行代码效率的问题,OP 说他看了代码后面的程序集,两行代码在程序集中是相同的。撇开离题不谈,我如何能够查看编译程序时创建的程序集代码。

我使用的是微软的 Visual C + + ,但我还想知道是否可以查看用 Visual Basic 编写的代码后面的程序集。

那么,如何查看用 C + + 和 VisualBasic 等高级语言编写的程序背后的汇编代码呢?

143574 次浏览

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

最简单的方法是激活调试器并检查 拆卸窗口

有几种方法:

  1. 您通常可以在 Visual Studio 中调试 C + + 时看到汇编代码(并且也可以看到 eclipse)。为此,在 Visual Studio 中在有问题的代码上放置一个断点,当调试器命中它时,右键单击并找到“ Go To Assembly”(或按 CTRL + ALT + D)

  2. 第二种方法是在编译时生成程序集清单。进入项目设置-> C/C + +-> 输出文件-> ASM 列表位置并填写文件名。同时选择“汇编输出”到“具有源代码的汇编”。

  3. 编译程序并使用任何第三方调试器。您可以使用 OllyDbg 或 WinDbg。你也可以使用 IDa (IDA Pro)。但这是一种非常强硬的方式。

红门。NET Refector 是一个非常棒的工具,它已经帮助过我很多次了。这个实用程序的好处之外,很容易显示您 MSIL 是,您可以分析很多第三方 DLL,并有反射器照顾转换 MSIL 到 C # 和 VB。

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

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


  • /FA 汇编代码;
  • 机器和装配代码
  • 源代码和汇编代码
  • /FAcs 机器、源代码和汇编代码; . cod

附加说明: 在调试汇编程序输出和发行版输出之间有很大的区别。第一个很好地学习了编译器如何从 C + + 生成汇编代码。第二种方法有助于学习编译器如何优化各种 C + + 结构。在这种情况下,一些 C + + 到高斯的转换并不明显。

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

Exe/dump/linumbers/disasm/out: foo.dis foo.dll

Pdb 需要可用才能获得符号

这个答案的早期版本(rextester.com 的“ hack”)现在基本上是多余的,因为 http://gcc.godbolt.org/为 ARM、 x86和 x86-64提供 CL 19 RC(针对 Windows 调用约定,不像那个站点上的 gcc、 clang 和 icc)。

Godbolt 编译器浏览器的设计是为了很好地格式化编译器的 asm 输出,去除指令的“噪音”,所以我强烈推荐使用它来查看 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 ...

typecat的 DOS 版本。我不想包含更多的代码,这会使我更难找到我想要的函数。(虽然使用 std: : string 和 ost 与这些目标背道而驰!一些 C 风格的字符串操作对它处理的字符串做了更多的假设(并且通过使用一个大缓冲区忽略了最大长度的安全性/分配) ,对于 GetModuleFileNameA的结果来说,总的机器代码要少得多

IDK 为什么,但 cout << p.string() << endl只显示基名(即文件名,没有目录) ,即使打印它的长度表明它不只是裸名。(Chromium48 on Ubuntu 15.10).在 cout中的某个位置,或者程序的标准输出和 Web 浏览器之间,可能有一些反斜杠转义处理。

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

使用 Visual Studio 6.0

点击菜单项“项目”

点击“设置”

选择 Tab 头 C/C + +

将“类别”更改为“列出文件”

在“列表文件类型”下将组合框从“无列表”更改为“使用机器码装配”

程序集源代码文件将作为.cod 文件出现在“发布”文件夹中