5

I have been looking at some simple C code and the different output from GCC using different optimization levels.

C code

#include <stdio.h>

int main() {
    int i = 0;

    while(i<10) {
            printf("Hello\n");
            i++;
    }

    i = 0;

    while(i<10) {
            printf("i: %d\n", i);
            i++;
    }

}

When I compile the code using -Os or -O2 the first loop works a bit differently. It it decrements instead of incrementing, and it is in two different ways. I am wondering why it decrements instead of incrementing like in the code, and the the small difference between -Os and -O2.

-Os compiled

0x400486 <main+6>       mov     edi,0x40068c
0x40048b <main+11>      call    0x400450 <puts@plt>
0x400490 <main+16>      dec     ebx
0x400492 <main+18>      jne     0x400486 <main+6>

-O2 compiled

0x400490 <main+16>      mov    edi,0x40069c
0x400495 <main+21>      call   0x400450 <puts@plt>
0x40049a <main+26>      sub    ebx,0x1
0x40049d <main+29>      jne    0x400490 <main+16> 
pank4j
  • 673
  • 4
  • 8

2 Answers2

7

By decrementing, compiler can make use of jne (jump if not equal/zero) which does the comparison (to zero) and jump in a single instruction. In case of incrementing, it would have to do a cmp/test (with 10) and then a conditional jump like jnz/jne. I believe it is a part of optimization.

-Os flag optimizes to bring down the code size. The code generated using -Os uses dec ebx instead of sub ebx, 0x1, since dec ebx is a 2-byte instruction while sub ebx, 0x1 is a 3-byte instruction (Note the address at which the next instruction begins). That explains the small difference.

pank4j
  • 673
  • 4
  • 8
5

Because I can't comment, I'll try to fix some inaccuracies in pnak4j's answer.

dec ebx is really a 1-byte instruction (I don't know why it appears to be 2-bytes). DEC sets the ZF flag accordingly to the result of (ebx-1) when: zero or not zero. Then, JNE does the jump if not zero (JNE/JNZ are the same). JMP is not a conditional jump, therefore it would not make much sense after CMP/TEST.

perror
  • 19,083
  • 29
  • 87
  • 150
Lain
  • 51
  • 1