Code Yarns ‍👨‍💻
Tech BlogPersonal Blog

How to generate assembly code using gcc

📅 2019-Dec-30 ⬩ ✍️ Ashwin Nanjappa ⬩ 📚 Archive

When we use GCC to compile C or C++ code, it directly generates the final object or executable file. For example, this command generates an a.out executable:

$ g++ foobar.cpp

I find it useful to generate assembly code to understand what the compiler is doing to my C++ code. To generate assembly code we essentially request GCC to stop before the assembly stage of compilation and dump what it has generated from the compiler backend.

To generate assembly code:

$ g++ -S foobar.cpp

This writes the assembly code to a foobar.s file. For x86 and x64 assembly code, the AT&T syntax is used by default.

To generate assembly code in Intel syntax:

$ g++ -S -masm=intel foobar.cpp

The assembly code generated by the above -S option does not have any annotations indicating which lines of the C++ code correspond to which assembly instructions.

To get assembly code with annotations of the C++ source code:

$ gcc -S -fverbose-asm foobar.cpp

This option adds two types of extra commentary. First, every statement of the C++ code appears in the assembly code. This makes it easy to identify which assembly code lines correspond to every C++ source line. Note that function definition lines from C++ do not appear though, but I can usually identify them by looking at their mangled label name. Second, every assembly code line that uses registers has a comment to its right indicating which variable from the C++ code is being read or written. I find this information takes off a huge burden when reading assembly code.

To get elaborate commentary in the assembly code:

$ gcc -g -Wa,-adhln foobar.cpp > foobar.s

The -adhln options are passed to the assembler since we prefixed it with -Wa. The -adhln options essentially ask the assembler to enable assembly code listings -a, omit debugging directives -d, include C++ source code -h, include assembly -l and omit other stuff -n.

The above option provides the most pleasing annotations for assembly code. Unlike the -fverbose-asm option, this one includes all the C++ source lines including function definition lines. However, this invocation does not have commentary beside each assembly line indicating which C++ variable is being held in registers in that line.

Thankfully, all these options can be combined to generate the most detailed annotated assembly code:

$ gcc -g -Wa,-adhln -fverbose-asm foobar.cpp > foobar.s

Tried with: GCC 7.4.0 and Ubuntu 18.04