ChatGPT解决这个技术问题 Extra ChatGPT

How to view the assembly behind the code using Visual C++?

I was reading another question pertaining the efficiency of two lines of code, and the OP said that he looked at the assembly behind the code and both lines were identical in assembly. Digression aside, how could I view the assembly code created when a program is compiled.

I'm using Microsoft's Visual C++, but I would also like to know if it's possible to view the assembly behind code written in Visual Basic.

So, how do I view the assembly code behind a program written in higher level languages like C++ and Visual Basic?

It's called an assembly listing in msvc as others have mentioned already. I created a simple plugin adding entries to the editor context menu to automate those tedious steps: marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils

i
inazaruk

There are several approaches:

You can normally see assembly code while debugging C++ in visual studio (and eclipse too). For this in Visual Studio put a breakpoint on code in question and when debugger hits it rigth click and find "Go To Assembly" ( or press CTRL+ALT+D ) Second approach is to generate assembly listings while compiling. For this go to project settings -> C/C++ -> Output Files -> ASM List Location and fill in file name. Also select "Assembly Output" to "Assembly With Source Code". Compile the program and use any third-party debugger. You can use OllyDbg or WinDbg for this. Also you can use IDA (interactive disassembler). But this is hardcore way of doing it.


Note that approach #2 doesn't work when compiling a static library with whole-program optimization enabled (in VS2010 at least). Which makes sense - the compiler hasn't generated the final code yet.
It is called "Goto Disassembly" in Visual Studio 2017
With approach #2, how can I see the assembly?
Should see an .asm file in the debug dir if you used default location.
"You can normally see assembly code while debugging C++ in visual studio " Whoa, I used godbolt and compiler output for this FOR YEARS while I could just get this in VS but didn't know. I missed this a lot. Thank you for opening my eyes, may you live for hundred!
g
greatwolf

Specify the /FA switch for the cl compiler. Depending on the value of the switch either only assembly code or high-level code and assembly code is integrated. The filename gets .asm file extension. Here are the supported values:

/FA Assembly code; .asm

/FAc Machine and assembly code; .cod

/FAs Source and assembly code; .asm

/FAcs Machine, source, and assembly code; .cod


V
Vladimir Obrizan

Additional note: there is big difference between Debug assembler output and Release one. The first one is good to learn how compiler produces assembler code from C++. The second one is good to learn how compiler optimizes various C++ constructs. In this case some C++-to-asm transformations are not obvious.


I noticed that when disassembling Debug executable it seems to unpack code while it's running, this doesn't happen on the Release version. Also when opening both with PEiD just the Debug version shows "Microsoft Visual C++ 8.0 [Debug]".
This is absolutely true. But it doesn't answer the question at all.
d
diapir

The easiest way is to fire the debugger and check the disassembly window.


P
Peter Cordes

The earlier version of this answer (a "hack" for rextester.com) is mostly redundant now that http://gcc.godbolt.org/ provides CL 19 RC for ARM, x86, and x86-64 (targeting the Windows calling convention, unlike gcc, clang, and icc on that site).

The Godbolt compiler explorer is designed for nicely formatting compiler asm output, removing the "noise" of directives, so I'd highly recommend using it to look at asm for simple functions that take args and return a value (so they won't be optimized away).

For a while, CL was available on http://gcc.beta.godbolt.org/ but not the main site, but now it's on both.

To get MSVC asm output from the http://rextester.com/l/cpp_online_compiler_visual online compiler: Add /FAs to the command line options. Have your program find its own path and work out the path to the .asm and dump it. Or run a disassembler on the .exe.

e.g. 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 is the DOS version of cat. I didn't want to include more code that would make it harder to find the functions I wanted to see the asm for. (Although using std::string and boost run counter to those goals! Some C-style string manipulation that makes more assumptions about the string it's processing (and ignores max-length safety / allocation by using a big buffer) on the result of GetModuleFileNameA would be much less total machine code.)

IDK why, but cout << p.string() << endl only shows the basename (i.e. the filename, without the directories), even though printing its length shows it's not just the bare name. (Chromium48 on Ubuntu 15.10). There's probably some backslash-escape processing at some point in cout, or between the program's stdout and the web browser.


@MichaelPetch: oh, turns out that is what I had tried. .c_str() prints what looks like a pointer. If you follow the link, you'll see code to hexdump a std::string (disabled with #if 0). It turns out the string is fine, but cout isn't getting it to the web browser. There aren't any non-ascii characters either, just backslashes.
I might be missing something but when you did subdir--; p /= *subdir; didn't you reduce p to just the file name? Or maybe I am misunderstanding what you are trying to print.
I guess I don't quite understand the subdir-- followed by p /= *subdir when subdir was originally p.end()
@MichaelPetch: updated comments. I needed to get the last directory component of the path to use as a filename. It does work, but it took me a long time to work out because I thought GetModuleFileNameA was just returning a.exe. It wasn't until I hexdumped it and printed the length that I knew it was working, and I could have the program manipulate the path, I just couldn't print the path
Yeah, seems to be the \\r (well \r when the compiler outputs it) part of the filename that it translated poorly when rendering for the web browser. Using p.generic_string() works but the backslashes are forward slashes.
j
jcopenha

In Visual C++ the project options under, Output Files I believe has an option for outputing the ASM listing with source code. So you will see the C/C++ source code and the resulting ASM all in the same file.


S
Steve Steiner

For MSVC you can use the linker.

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

foo.pdb needs to be available to get symbols


D
Dave L

Red Gate's .NET Reflector is a pretty awesome tool that has helped me out more than a few times. The plus side of this utility outside of easily showing you MSIL is that you can analyze a lot of third-party DLLs and have the Reflector take care of converting MSIL to C# and VB.

I'm not promising the code will be as clear as source but you shouldn't have much trouble following it.


Note: only applicable to managed assemblies not to disassembly as in assembler, asm.
Good point, I read it as a "are the two lines of code the same in the assembly" instead of "are the two lines of code the same in assembly"
It will only work on dotnet apps, Not Visual C++ linker or compiler.
A
Aabbee

If you are talking about debugging to see the assembly code, the easiest way is Debug->Windows->Disassembly (or Alt-8). This will let you step into a called function and stay in Disassembly.


T
Tim Pearson

Using Visual Studio 6.0

Click on Menu item "Project"

Click on "Settings"

Select tab header C/C++

Change "Category" to "Listing files"

Under "Listing file type" change the combobox from "No listing" to "Assembly with machine code"

Assembly source code files will appear in "Release" folder as .cod files