How to See the Assembly Code for a C++ Program

How can I view assembly code produced for C functions?

You may add the -S tag to see the assembly code.

Like for a file TEST.c, with gcc, do,

gcc TEST.c -S

clang also outputs the assembly code with a similar -S tag.

After that just look for a file with a .S extension.

How can I see the assembly code for a C++ program?

Ask the compiler

If you are building the program yourself, you can ask your compiler to emit assembly source. For most UNIX compilers use the -S switch.

  • If you are using the GNU assembler, compiling with -g -Wa,-alh will give intermixed source and assembly on stdout (-Wa asks compiler driver to pass options to assembler, -al turns on assembly listing, and -ah adds "high-level source" listing):

    g++ -g -c -Wa,-alh foo.cc

  • For Visual Studio, use /FAsc.

Peek into a binary

If you have a compiled binary,

  • use objdump -d a.out on UNIX (also works for cygwin),
  • dumpbin /DISASM foo.exe on Windows.

Use your debugger

Debuggers could also show disassembly.

  • Use disas command in GDB.

    Use set disassembly-flavor intel if you prefer Intel syntax.
  • or the disassembly window of Visual Studio on Windows.

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

There are several approaches:

  1. 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 )

  2. 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".

  3. 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.

How to view assembly code in codeblocks?

The compiler options:

-c  # compile only (don't link)
-S # assemble only (don't compile or link)
-E # preprocess only (don't assemble, compile or link)

are mutually exclusive. Furthermore, you cannot specify:

-o foo.o    # write output to `foo.o`

if you are specifying multiple input source files.

You are adding -S a43.c to the Other compiler options. That means you
are adding them to the existing compilation options for your project. Those
options already include -c by default, because that's the option to compile,
so adding -S conflicts with -c.

-S does not take any argument, specifically no filename argument. It tells
gcc only to assemble (not compile or link) the input files, whatever they are. So adding:

-S a43.c

as well as adding -S to the existing options, adds an input file,
a43.c, to the project's compiler options. But of course Code::Blocks will add the
name of an input file to the compiler options whenever it compiles one of the
files in the project. So there will be two source filenames in the commandline.
Hence the error:

cannot specify -o with -c, -S or -E with multiple files

If you want to modify your Code::Blocks compilation options so that they will also
produce the assembly listing of each file compiled, then remove

-S a43.c

from Other compiler options and replace it with

-save-temps

Then, whenever gcc compiles a file foo.c in the project, it will save the
intermediate files as:

foo.s   # The assembly
foo.i # The preprocessed source

These files will be saved in the same directory as foo.c itself; not in the
directory where the object file foo.o is output.

See the documentation of -save-temps in the GCC manual

Assembly Code from C program

If you compile your function as is, in optimization level3, -O3 the entire function is optimized out. This is because there is no return value and py and ty are anyways discarded after the function.

For reference the code is below

    .globl  decod
.def decod; .scl 2; .type 32; .endef
.seh_proc decod
decod:
.seh_endprologue
ret
.seh_endproc

If however, you add a return py; at the end the code generated is as follows.

    .globl  decod
.def decod; .scl 2; .type 32; .endef
.seh_proc decod
decod:
.seh_endprologue
subl %r8d, %edx
movl %edx, %eax
imull %edx, %ecx
sall $31, %eax
sarl $31, %eax
xorl %ecx, %eax
ret
.seh_endproc

This is functionally identical to what you are expecting.

View Both Assembly and C code

You can run gdb in Text User Interface (TUI) mode:

gdb -tui <your-binary>
(gdb) b main
(gdb) r
(gdb) layout split

The layout split command divides the window into two parts - one of them displaying the source code, the other one the corresponding assembly.
A few others tricks:

  • set disassembly-flavor intel - if your prefer intel notation
  • set print asm-demangle - demangles C++ names in assembly view
  • ni - next instruction
  • si - step instruction

If you do not want to use the TUI mode (e.g. your terminal does not like it), you can always do:

x /12i $pc

which means print 12 instructions from current program counter address - this also works with the tricks above (demangling, stepping instructions, etc.).

The "x /12i $pc" trick works in both gdb and cgdb, whereas "layout split" only works in gdb.

Enjoy :)



Related Topics



Leave a reply



Submit