How to Generate Mixed Source and Assembly List from Source Code using GCC
Posted on In Linux, ProgrammingWhen debugging and optimizing programs, developers sometimes need to generate and investigate into the assembly generated by the compiler. Generating a mixed source and assembly list will help a lot for debugging and optimization. gcc
can achieve this by working with the assembler.
Table of Contents
Generate assembly list mixed with the source code
Just add these gcc compile options:
-Wa,-adhln -g
The command:
$ gcc -Wa,-adhln -g source_code.c > assembly_list.s
The options:
-g: Produce debugging information
-Wa,option: Pass option as an option to the assembler
-adhln:
a: turn on listings
d: omit debugging directives
n: omit forms processing
h: include high-level source
l: include assembly
One example
The source code:
helloworld.c:
#include <stdio.h>
int main()
{
printf("Hello world!\n");
return 0;
}
The command:
$ gcc -Wa,-adhln -g helloworld.c > helloworld.s
helloworld.s:
...
0:helloworld.c **** #include <stdio.h>
1:helloworld.c ****
2:helloworld.c **** int main()
3:helloworld.c **** {
19 .loc 1 4 0
20 .cfi_startproc
21 0000 55 pushq %rbp
22 .LCFI0:
23 .cfi_def_cfa_offset 16
24 0001 4889E5 movq %rsp, %rbp
25 .cfi_offset 6, -16
26 .LCFI1:
27 .cfi_def_cfa_register 6
4:helloworld.c **** printf("Hello world!\n");
28 .loc 1 5 0
29 0004 BF000000 movl $.LC0, %edi
29 00
30 0009 E8000000 call puts
30 00
5:helloworld.c **** return 0;
31 .loc 1 6 0
32 000e B8000000 movl $0, %eax
32 00
6:helloworld.c **** }
...
Another example with more than 1 source files
You may also use the method here for compiling programs from more than 1 C source files. For example, a project contains 2 source files as follows.
fun1.c:
#include <stdio.h>
void fun1()
{
printf("Hello world!\n");
}
main.c:
#include <stdio.h>
void fun1();
int main()
{
fun1();
return 0;
}
You can generate the source-assembly list by
$ gcc -Wa,-adhln -g fun1.c main.c -o a > helloworld.s
For your reference, the helloworld.s file is as follows.
1 .file "fun1.c"
2 .text
3 .Ltext0:
4 .section .rodata
5 .LC0:
6 0000 48656C6C .string "Hello world!"
6 6F20776F
6 726C6421
6 00
7 .text
8 .globl fun1
10 fun1:
11 .LFB0:
12 .file 1 "fun1.c"
1:fun1.c **** #include <stdio.h>
2:fun1.c ****
3:fun1.c **** void fun1()
4:fun1.c **** {
13 .loc 1 4 0
14 .cfi_startproc
15 0000 55 pushq %rbp
16 .cfi_def_cfa_offset 16
17 .cfi_offset 6, -16
18 0001 4889E5 movq %rsp, %rbp
19 .cfi_def_cfa_register 6
5:fun1.c **** printf("Hello world!\n");
20 .loc 1 5 0
21 0004 BF000000 movl $.LC0, %edi
21 00
22 0009 E8000000 call puts
22 00
6:fun1.c **** }
23 .loc 1 6 0
24 000e 5D popq %rbp
25 .cfi_def_cfa 7, 8
26 000f C3 ret
27 .cfi_endproc
28 .LFE0:
30 .Letext0:
1 .file "main.c"
2 .text
3 .Ltext0:
4 .globl main
6 main:
7 .LFB0:
8 .file 1 "main.c"
1:main.c **** #include <stdio.h>
2:main.c **** void fun1();
3:main.c **** int main()
4:main.c **** {
9 .loc 1 4 0
10 .cfi_startproc
11 0000 55 pushq %rbp
12 .cfi_def_cfa_offset 16
13 .cfi_offset 6, -16
14 0001 4889E5 movq %rsp, %rbp
15 .cfi_def_cfa_register 6
5:main.c **** fun1();
16 .loc 1 5 0
17 0004 B8000000 movl $0, %eax
17 00
18 0009 E8000000 call fun1
18 00
6:main.c **** return 0;
19 .loc 1 6 0
20 000e B8000000 movl $0, %eax
20 00
7:main.c **** }
21 .loc 1 7 0
22 0013 5D popq %rbp
23 .cfi_def_cfa 7, 8
24 0014 C3 ret
25 .cfi_endproc
26 .LFE0:
28 .Letext0:
Excellent!
Hi,
I have found the above commands you have suggested quite useful but i would like to know how can i use this command when there are mutiple files of code to be executed and I am interested in the assembly code of only one of those files ?
You can use the same method to generate the source-assembly list from several source files. Note that the line numbers are followed with source file names like “1:fun1.c”. You may only check the parts that you are interested in.
Hi Sir,
Thank you very much for your explanation.
I have one query, So from the above option we can get the list of source file but is it possible that “Can we get to know what and particular source file is going to be used for particular executable file (In case when source code generate two or more executable’s)” ..?
Lets say:
We have 5 source file, and 3 source files are used for “a.out” and rest 2 source files are used for “b.out” then “How can we get to know it that which source files is used for which “executable file”..?
Thanks in advance
For your purpose, I feel checking the Makefile or other files specifying the dependence of files in your project will be better.
Thanks a lot, will check the same.
How can I make gcc within Eclipse IDE being aware of my assembly code and allow me to debug it?
great post,
Is their any tool to identify what are all different register used in assembly code generated by gcc or any other compiler? or is their any way we can find out which registers are used in assembly code and total access count of these registers.
Different compilers may generate different instruction flows for the same program. It may not be easy to do a side-by-side comparison. There are only a small number of registers in the common CPU ISAs. To get best performance, compilers usually generate instructions to use as registers as much as possible.
The total access count of the registers used may be counted during runtime and may be different with different input to the programs. If you need such info, you may use some techniques like those used in JIT compilers or virtual machines to “record” the instructions executed and count the register usage. But I am not aware of any existing tools doing this.
Thanks a lot Eric for inputs.
I really appreciate you quick help.
This is very helpful. Could you please post also information what are corresponding compiler options for g++?
getting errors at the end
d:/progs/gcc_riscv_v12/bin/../lib/gcc/riscv-none-elf/12.2.0/../../../../riscv-none-elf/bin/ld.exe: warning: cannot find entry symbol _start; defaulting to 0000000000010094
d:/progs/gcc_riscv_v12/bin/../lib/gcc/riscv-none-elf/12.2.0/../../../../riscv-none-elf/bin/ld.exe: C:\Users\mrx23dot\AppData\Local\Temp\cc8KCAnd.o: in function `adc_filter_task’:
D:\DRIVE\Projects\FW_ch32v003_template\build/..\src\adcFilter/adcFilter.c:45: undefined reference to `adc_read’
d:/progs/gcc_riscv_v12/bin/../lib/gcc/riscv-none-elf/12.2.0/../../../../riscv-none-elf/bin/ld.exe: C:\Users\mrx23dot\AppData\Local\Temp\cc8KCAnd.o: in function `adc_readFilt’:
D:\DRIVE\Projects\FW_ch32v003_template\build/..\src\adcFilter/adcFilter.c:61: undefined reference to `assert_halt’
collect2.exe: error: ld returned 1 exit status
Tries to do more than asm?