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

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:

About Eric Zhiqiang Ma

Eric Zhiqiang Ma is interested in operating systems and distributed computing and processing systems. Find Eric on Facebook, Twitter, LinkedIn and Google+. The views or opinions expressed here are solely Eric's own and do not necessarily represent those of any third parties.

4 comments:

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

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

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>