Ground Embedded KO Subscribe

Notes / Machine Code & Assembly

C against assembly: what optimisation options change

Disassemble a simple C function and match it line by line, then compare how differently -O0 and -O2 build the same code.

GROUND EMBEDDED · NOTEMachine Code & Assembly 04C versus assembly 1ldr r0, =0x40020014 2ldr r1, [r0] 3orr r1, r1, #0x20 4str r1, [r0] 5bl main 6b .

How to view a disassembly

arm-none-eabi-objdump -d -S firmware.elf > fw.lst

With -S the C source and the instructions are interleaved. In STM32CubeIDE, open the Disassembly window while debugging.

The same function, different results

-O0every variable via memory-O2kept in registers, shorter code-Ossize first
The same C code gives different results depending on the optimisation option.
int sum(const int *a, int n) {
    int s = 0;
    for (int i = 0; i < n; i++) s += a[i];
    return s;
}
  • -O0: the variables s and i are stored to the stack and read back every time. Good for debugging, but slow.
  • -O2: s and i stay in registers, and the loop runs by incrementing the pointer directly. The instruction count falls to less than half.

Bugs that optimisation exposes

If behaviour goes wrong only at -O2, it is usually one of these.

  • No volatile on a variable shared with an interrupt → the read is hoisted out of the loop
  • Undefined behaviour (signed overflow, uninitialised variables)
  • A delay loop for (i = 0; i < 1000; i++); vanishes entirely

Read it not as "optimisation breaks things" but as "optimisation exposed a bug that was already there".

FREE PDFGet the 3 free ebooksIf you want to keep reading this topic as one book: BLDC motor control, serial communication and sensors at book length. PDFs are in Korean.Get them free →