Post

C -- volatile

When using GCC to add breakpoint to a specific location, sometimes I am worried that this piece of code may be optimized away by the compiler. Disabling optimization can rule out my concern, but I also wonder whether there is a language semantic that prohibits a line of code being optimized away. The answer is volatile.

Let’s do a simple experiment.

1
2
3
4
5
/* test.c */
int main() {
  int meaning_of_life = 42;
  return 0;
}

gcc -S test.c -03 generates below assembly in MacOS M1.

1
2
3
4
5
6
7
8
9
10
11
12
        .section        __TEXT,__text,regular,pure_instructions
        .build_version macos, 14, 0     sdk_version 14, 5
        .globl  _main                           ; -- Begin function main
        .p2align        2
_main:                                  ; @main
        .cfi_startproc
; %bb.0:
        mov     w0, #0
        ret
        .cfi_endproc
                                        ; -- End function
.subsections_via_symbols

mov w0 #0 loads intermediate 0 to register w0 which is used to set the return value of the function. As expected, int meaning_of_life = 1; is optimized away. However, if we change this line to

1
volatile int meaning_of_life = 42;

we get below assembly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        .section        __TEXT,__text,regular,pure_instructions
        .build_version macos, 14, 0     sdk_version 14, 5
        .globl  _main                           ; -- Begin function main
        .p2align        2
_main:                                  ; @main
        .cfi_startproc
; %bb.0:
        sub     sp, sp, #16
        .cfi_def_cfa_offset 16
        mov     w8, #42
        str     w8, [sp, #12]
        mov     w0, #0
        add     sp, sp, #16
        ret
        .cfi_endproc
                                        ; -- End function
.subsections_via_symbols

Ignore the function prologue and epilogue. mov w8 #42 loads intermediate value 42 to register w8. str w8, [sp, #12] stores the value in register w8 into the stack at an offset of 12 bytes from the current stack pointer, which is the location of local variable meaning_of_life in the stack.

OK. A volatile variable indeed prevents compiler optimizing it away.

This post is licensed under CC BY 4.0 by the author.