Skip to content

Latest commit

 

History

History
179 lines (148 loc) · 5.71 KB

looking-at-the-generated-asm.rst

File metadata and controls

179 lines (148 loc) · 5.71 KB

Looking at the generated assembler

In the previous section, we looked at how the :program:`gcc` driver program invokes various tools to get its job done. For me, the most interesting part of that process is the conversion from C source code to machine code (expressed in the form of assembler) done by the compiler, :program:`cc1`.

We can see this part of the process more directly by invoking :program:`gcc` with the :option:`-S` option (upper-case "S"):

$ gcc -S hello.c

telling it to merely create an assembler file (with a lower-case :file:`.s` extension), without doing the later stages we talked about above:

         cc1
hello.c -----> hello.s
gcc -S hello.c

and in addition to the :file:`hello` executable we built earlier, we now have a :file:`hello.s` file:

$ ls
hello  hello.c  hello.s

Looking in the :file:`hello.s` file we see the generated assembler:

      .file   "hello.c"
      .text
      .section        .rodata
.LC0:
      .string "hello world"
      .text
      .globl  main
      .type   main, @function
main:
.LFB0:
      .cfi_startproc
      pushq   %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset 6, -16
      movq    %rsp, %rbp
      .cfi_def_cfa_register 6
      movl    $.LC0, %edi
      call    puts
      movl    $0, %eax
      popq    %rbp
      .cfi_def_cfa 7, 8
      ret
      .cfi_endproc
.LFE0:
      .size   main, .-main
      .ident  "GCC: (GNU) 10.3.1 20210422 (Red Hat 10.3.1-1)"
      .section        .note.GNU-stack,"",@progbits

It's not important yet to be able to fully understand the assembler, but for now just know that we have some metadata at the top, followed by the user's :c:func:`main` function, and then some trailing metadata.

You can even see how the assembler relates to the C code by passing :option:`-fverbose-asm` to :program:`gcc`:

$ gcc -S hello.c -fverbose-asm

which leads to this in the output :file:`hello.s` file:

      .file   "hello.c"
# GNU C17 (GCC) version 10.3.1 20210422 (Red Hat 10.3.1-1) (x86_64-redhat-linux)
#     compiled by GNU C version 10.3.1 20210422 (Red Hat 10.3.1-1), GMP version 6.2.0, MPFR version 4.1.0-p9, MPC version 1.1.0, isl version none
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# options passed:  hello.c -mtune=generic -march=x86-64 -fverbose-asm
# options enabled:  -faggressive-loop-optimizations -fallocation-dce
# -fasynchronous-unwind-tables -fauto-inc-dec -fdelete-null-pointer-checks
# -fdwarf2-cfi-asm -fearly-inlining -feliminate-unused-debug-symbols
# -feliminate-unused-debug-types -ffp-int-builtin-inexact -ffunction-cse
# -fgcse-lm -fgnu-unique -fident -finline-atomics -fipa-stack-alignment
# -fira-hoist-pressure -fira-share-save-slots -fira-share-spill-slots
# -fivopts -fkeep-static-consts -fleading-underscore -flifetime-dse
# -fmath-errno -fmerge-debug-strings -fpeephole -fplt
# -fprefetch-loop-arrays -freg-struct-return
# -fsched-critical-path-heuristic -fsched-dep-count-heuristic
# -fsched-group-heuristic -fsched-interblock -fsched-last-insn-heuristic
# -fsched-rank-heuristic -fsched-spec -fsched-spec-insn-heuristic
# -fsched-stalled-insns-dep -fschedule-fusion -fsemantic-interposition
# -fshow-column -fshrink-wrap-separate -fsigned-zeros
# -fsplit-ivs-in-unroller -fssa-backprop -fstdarg-opt
# -fstrict-volatile-bitfields -fsync-libcalls -ftrapping-math -ftree-cselim
# -ftree-forwprop -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
# -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop
# -ftree-reassoc -ftree-scev-cprop -funit-at-a-time -funwind-tables
# -fverbose-asm -fzero-initialized-in-bss -m128bit-long-double -m64 -m80387
# -malign-stringops -mavx256-split-unaligned-load
# -mavx256-split-unaligned-store -mfancy-math-387 -mfp-ret-in-387 -mfxsr
# -mglibc -mieee-fp -mlong-double-80 -mmmx -mno-sse4 -mpush-args -mred-zone
# -msse -msse2 -mstv -mtls-direct-seg-refs -mvzeroupper

      .text
      .section        .rodata
.LC0:
      .string "hello world"
      .text
      .globl  main
      .type   main, @function
main:
.LFB0:
      .cfi_startproc
      pushq   %rbp    #
      .cfi_def_cfa_offset 16
      .cfi_offset 6, -16
      movq    %rsp, %rbp      #,
      .cfi_def_cfa_register 6
# hello.c:4:   printf ("hello world\n");
      movl    $.LC0, %edi     #,
      call    puts    #
# hello.c:5:   return 0;
      movl    $0, %eax        #, _3
# hello.c:6: }
      popq    %rbp    #
      .cfi_def_cfa 7, 8
      ret
      .cfi_endproc
.LFE0:
      .size   main, .-main
      .ident  "GCC: (GNU) 10.3.1 20210422 (Red Hat 10.3.1-1)"
      .section        .note.GNU-stack,"",@progbits

In particular, looking at the heart of the :c:func:`main` function we now have comments showing us how the some of the assembler relates to specific lines in the C source file:

# hello.c:4:   printf ("hello world\n");
      movl    $.LC0, %edi     #,
      call    puts    #
# hello.c:5:   return 0;
      movl    $0, %eax        #, _3
# hello.c:6: }
      popq    %rbp    #
      .cfi_def_cfa 7, 8
      ret

We'll look at how :program:`cc1` actually turns the C into assembler in the next section.