Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler code generation comparisons

Ok, so all started here: Unsigned integer and unsigned char holding same value yet behaving differently why?

I wrote the following application to understand what happens behind the scenes (ie, how the compiler is handling this issue).

#include <stdio.h>

int main()
{
  {
  unsigned char k=-1;
  if(k==-1)
  {
    puts("uc ok\n");
  }
  }

  {
  unsigned int k=-1;
  if(k==-1)
  {
    puts("ui ok");
  }
  }
}

And while compiling it with GCC like:

gcc -O0 -S -masm=intel h.c 

I get the following assembly file:

    .file   "h.c"
    .intel_syntax noprefix
    .section        .rodata
.LC0:
    .string "ui ok"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    push    rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov     rbp, rsp
    .cfi_def_cfa_register 6
    sub     rsp, 16
    mov     BYTE PTR [rbp-1], -1
    mov     DWORD PTR [rbp-8], -1
    cmp     DWORD PTR [rbp-8], -1
    jne     .L3
    mov     edi, OFFSET FLAT:.LC0
    call    puts
.L3:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section        .note.GNU-stack,"",@progbits

And to my big surprise the first check is NOT EVEN THERE.

But, if I compile the same thing with Microsoft Visual C++ (2010), I get (I have cut off a lot of garbage from this listing, that's why it's not so valid):

00B81780  push        ebp  
00B81781  mov         ebp,esp  
00B81783  sub         esp,0D8h  
00B81789  push        ebx  
00B8178A  push        esi  
00B8178B  push        edi  
00B8178C  lea         edi,[ebp-0D8h]  
00B81792  mov         ecx,36h  
00B81797  mov         eax,0CCCCCCCCh  
00B8179C  rep stos    dword ptr es:[edi]  
00B8179E  mov         byte ptr [k],0FFh  
00B817A2  movzx       eax,byte ptr [k]  
00B817A6  cmp         eax,0FFFFFFFFh  
00B817A9  jne         wmain+42h (0B817C2h)  
00B817AB  mov         esi,esp  
00B817AD  push        offset string "uc ok\n" (0B857A8h)  
00B817B2  call        dword ptr [__imp__puts (0B882ACh)]  
00B817B8  add         esp,4  
00B817BB  cmp         esi,esp  
00B817BD  call        @ILT+435(__RTC_CheckEsp) (0B811B8h)  
00B817C2  mov         dword ptr [k],0FFFFFFFFh  
00B817C9  cmp         dword ptr [k],0FFFFFFFFh  
00B817CD  jne         wmain+66h (0B817E6h)  
00B817CF  mov         esi,esp  
00B817D1  push        offset string "ui ok" (0B857A0h)  
00B817D6  call        dword ptr [__imp__puts (0B882ACh)]  
00B817DC  add         esp,4  
00B817DF  cmp         esi,esp  
00B817E1  call        @ILT+435(__RTC_CheckEsp) (0B811B8h)  

The question is: Why is this happening? Why does GCC "skip" the first IF and how can I force GCC to not to skip it? Optimizations are disabled, but it seems it still optimizes away something ...

like image 285
Ferenc Deak Avatar asked Dec 26 '22 03:12

Ferenc Deak


1 Answers

My guess (I'm not a GCC developer) is that it does enough static analysis to prove to itself that the first if's test is never true.

This shouldn't be too hard, since there is no code between the initialization and the test, there is no way any side-effect or external entity could change the variable.

Just for curiosity, try making the variable static and/or volatile to see if anything changes.

like image 166
unwind Avatar answered Jan 07 '23 12:01

unwind