我正在阅读另一个关于两行代码效率的问题,OP 说他查看了代码后面的程序集,两行在程序集中是相同的。题外话,如何查看程序编译时创建的汇编代码。
我正在使用 Microsoft 的 Visual C++,但我也想知道是否可以查看用 Visual Basic 编写的代码背后的程序集。
那么,如何查看用 C++ 和 Visual Basic 等高级语言编写的程序背后的汇编代码?
有几种方法:
在 Visual Studio(以及 Eclipse)中调试 C++ 时,您通常可以看到汇编代码。为此,在 Visual Studio 中,在有问题的代码上放置一个断点,当调试器点击它时,单击并找到“Go To Assembly”(或按 CTRL+ALT+D)第二种方法是在编译时生成程序集列表。为此,请转到项目设置 -> C/C++ -> 输出文件 -> ASM 列表位置并填写文件名。还要选择“Assembly Output”到“Assembly With Source Code”。编译程序并使用任何第三方调试器。为此,您可以使用 OllyDbg 或 WinDbg。您也可以使用 IDA(交互式反汇编程序)。但这是做这件事的核心方式。
为 cl 编译器指定 /FA 开关。根据开关的值,要么只集成汇编代码,要么集成高级代码和汇编代码。文件名获得 .asm 文件扩展名。以下是支持的值:
/FA 汇编代码; .asm
/FAc 机器和汇编代码; .鳕鱼
/FAs 源代码和汇编代码; .asm
/FAcs 机器、源代码和汇编代码; .鳕鱼
附加说明:Debug 汇编器输出和 Release 1 之间存在很大差异。第一个很好地了解编译器如何从 C++ 生成汇编代码。第二个很好地了解编译器如何优化各种 C++ 结构。在这种情况下,一些 C++ 到 asm 的转换并不明显。
最简单的方法是启动调试器并检查反汇编窗口。
由于 http://gcc.godbolt.org/ 为 ARM、x86 和 x86-64(针对 Windows 调用约定)提供了 CL 19 RC,因此此答案的早期版本(rextester.com 的“hack”)大多是多余的,与该站点上的 gcc、clang 和 icc 不同)。
Godbolt 编译器资源管理器旨在很好地格式化编译器 asm 输出,消除指令的“噪音”,因此我强烈建议使用它来查看 asm 以获取带有 args 并返回值的简单函数(所以它们不会是优化了)。
有一段时间,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
是 cat
的 DOS 版本。我不想包含更多代码,这会使找到我想查看 asm 的函数变得更加困难。 (尽管使用 std::string 和 boost 与这些目标背道而驰!一些 C 风格的字符串操作对它正在处理的字符串做出更多假设(并通过使用大缓冲区忽略最大长度安全/分配){ 4} 总机器码会少得多。)
IDK 为什么,但 cout << p.string() << endl
只显示基本名称(即文件名,没有目录),即使打印它的长度显示它不仅仅是裸名。 (Ubuntu 15.10 上的 Chromium48)。在 cout
中的某个点,或在程序的标准输出和网络浏览器之间,可能有一些反斜杠转义处理。
.c_str()
打印看起来像指针的内容。如果您点击该链接,您将看到用于十六进制转储 std::string
的代码(使用 #if 0
禁用)。事实证明该字符串很好,但 cout
没有将它传送到 Web 浏览器。也没有任何非ASCII字符,只有反斜杠。
subdir--; p /= *subdir;
时,您没有将 p 简化为文件名吗?或者,也许我误解了您要打印的内容。
subdir
最初是 p.end()
时 p /= *subdir
后面的 subdir--
GetModuleFileNameA
只是返回 a.exe
。直到我对它进行十六进制转储并打印出我知道它正在工作的长度,并且我可以让程序操纵路径,我只是无法打印路径
\\r
(当编译器输出它时是 \r
)部分,它在为 Web 浏览器呈现时翻译得很差。使用 p.generic_string()
有效,但反斜杠是正斜杠。
在 Visual C++ 中,Output Files 下的项目选项我相信有一个用于输出带有源代码的 ASM 列表的选项。因此,您将在同一个文件中看到 C/C++ 源代码和生成的 ASM。
对于 MSVC,您可以使用链接器。
link.exe /dump /linenumbers /disasm /out:foo.dis foo.dll
foo.pdb 需要可用于获取符号
Red Gate's .NET Reflector 是一个非常棒的工具,它帮助了我很多次。除了轻松向您展示 MSIL 之外,此实用程序的优点是您可以分析许多第三方 DLL,并让 Reflector 负责将 MSIL 转换为 C# 和 VB。
我不保证代码会像源代码一样清晰,但你应该不会有太多麻烦。
如果您正在谈论调试以查看汇编代码,最简单的方法是Debug->Windows->Disassembly(或Alt-8)。这将让您进入一个被调用的函数并留在反汇编中。
使用 Visual Studio 6.0
单击菜单项“项目”
点击“设置”
选择选项卡标题 C/C++
将“类别”更改为“列出文件”
在“列出文件类型”下,将组合框从“无列表”更改为“使用机器代码组装”
汇编源代码文件将作为 .cod 文件出现在“Release”文件夹中
不定期副业成功案例分享