ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

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

i
inazaruk

有几种方法:

在 Visual Studio(以及 Eclipse)中调试 C++ 时,您通常可以看到汇编代码。为此,在 Visual Studio 中,在有问题的代码上放置一个断点,当调试器点击它时,单击并找到“Go To Assembly”(或按 CTRL+ALT+D)第二种方法是在编译时生成程序集列表。为此,请转到项目设置 -> C/C++ -> 输出文件 -> ASM 列表位置并填写文件名。还要选择“Assembly Output”到“Assembly With Source Code”。编译程序并使用任何第三方调试器。为此,您可以使用 OllyDbg 或 WinDbg。您也可以使用 IDA(交互式反汇编程序)。但这是做这件事的核心方式。


请注意,方法#2 在编译启用了全程序优化的静态库时不起作用(至少在 VS2010 中)。这是有道理的——编译器还没有生成最终代码。
在 Visual Studio 2017 中称为“Goto Disassembly”
使用方法 #2,我如何查看程序集?
如果您使用默认位置,应该在调试目录中看到一个 .asm 文件。
“您通常可以在 Visual Studio 中调试 C++ 时看到汇编代码”哇,我多年来一直使用 Godbolt 和编译器输出,而我只能在 VS 中得到它但不知道。我非常想念这个。谢谢你开我的眼睛,愿你百岁!
g
greatwolf

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

/FA 汇编代码; .asm

/FAc 机器和汇编代码; .鳕鱼

/FAs 源代码和汇编代码; .asm

/FAcs 机器、源代码和汇编代码; .鳕鱼


V
Vladimir Obrizan

附加说明:Debug 汇编器输出和 Release 1 之间存在很大差异。第一个很好地了解编译器如何从 C++ 生成汇编代码。第二个很好地了解编译器如何优化各种 C++ 结构。在这种情况下,一些 C++ 到 asm 的转换并不明显。


我注意到,在反汇编 Debug 可执行文件时,它似乎在运行时解压缩了代码,这在 Release 版本上不会发生。同样,当使用 PEiD 打开两者时,调试版本会显示“Microsoft Visual C++ 8.0 [Debug]”。
这是绝对正确的。但它根本没有回答这个问题。
d
diapir

最简单的方法是启动调试器并检查反汇编窗口。


P
Peter Cordes

由于 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 ...

typecat 的 DOS 版本。我不想包含更多代码,这会使找到我想查看 asm 的函数变得更加困难。 (尽管使用 std::string 和 boost 与这些目标背道而驰!一些 C 风格的字符串操作对它正在处理的字符串做出更多假设(并通过使用大缓冲区忽略最大长度安全/分配){ 4} 总机器码会少得多。)

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


@MichaelPetch:哦,原来是我尝试过的.c_str() 打印看起来像指针的内容。如果您点击该链接,您将看到用于十六进制转储 std::string 的代码(使用 #if 0 禁用)。事实证明该字符串很好,但 cout 没有将它传送到 Web 浏览器。也没有任何非ASCII字符,只有反斜杠。
我可能遗漏了一些东西,但是当您执行 subdir--; p /= *subdir; 时,您没有将 p 简化为文件名吗?或者,也许我误解了您要打印的内容。
我想我不太明白 subdir 最初是 p.end()p /= *subdir 后面的 subdir--
@MichaelPetch:更新评论。我需要获取路径的最后一个目录组件以用作文件名。它确实有效,但我花了很长时间才解决,因为我认为 GetModuleFileNameA 只是返回 a.exe。直到我对它进行十六进制转储并打印出我知道它正在工作的长度,并且我可以让程序操纵路径,我只是无法打印路径
是的,似乎是文件名的 \\r(当编译器输出它时是 \r)部分,它在为 Web 浏览器呈现时翻译得很差。使用 p.generic_string() 有效,但反斜杠是正斜杠。
j
jcopenha

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


S
Steve Steiner

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

link.exe /dump /linenumbers /disasm /out:foo.dis foo.dll

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


D
Dave L

Red Gate's .NET Reflector 是一个非常棒的工具,它帮助了我很多次。除了轻松向您展示 MSIL 之外,此实用程序的优点是您可以分析许多第三方 DLL,并让 Reflector 负责将 MSIL 转换为 C# 和 VB。

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


注意:仅适用于托管程序集,不适用于 assembler、asm 中的反汇编。
好点,我将其读作“程序集中的两行代码是否相同”而不是“程序集中的两行代码是否相同”
它仅适用于 dotnet 应用程序,不适用于 Visual C++ 链接器或编译器。
A
Aabbee

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


T
Tim Pearson

使用 Visual Studio 6.0

单击菜单项“项目”

点击“设置”

选择选项卡标题 C/C++

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

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

汇编源代码文件将作为 .cod 文件出现在“Release”文件夹中


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅