Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is such strange code generated?

Tags:

x86

assembly

g++

Consider a piece of C++ code:

int main()
{
    volatile int a=0;
    if(!a)
        ++a;
}

I compile it on amd64 system with g++ (Ubuntu 4.8.1-2ubuntu1~12.04) with command g++ test.cpp -S -o test.S -masm=intel and get the following code:

...
    mov eax, DWORD PTR [ebp-4]
    test    eax, eax
    sete    al
    test    al, al
    je  .L2
    mov eax, DWORD PTR [ebp-4] ; don't use result of sete
    add eax, 1
    mov DWORD PTR [ebp-4], eax
.L2:
    mov eax, 0 ; also drop result of sete
...

This code really surprises me. At first I thought it has something to do with 64-bit mode. But when I tried to compile with -m32, this bit remained the same.

Why does it check eax for being zero and then recheck the result once more after setting al to ZF? Why doesn't it just do test eax,eax\n jne .L2?

like image 965
Ruslan Avatar asked Dec 28 '25 23:12

Ruslan


1 Answers

I think it has to do with how bool is handled differently in C and C++. In your code, the if(!a) first converts a to a bool (that's what the test eax, eax; sete al does), and then tests that boolean (in al) for true/false.

If you rename as .c and compile the same code with gcc, it generates the expected code

    mov DWORD PTR [rbp-4], 0
    mov eax, DWORD PTR [rbp-4]
    test    eax, eax
    jne .L3
    mov eax, DWORD PTR [rbp-4]
    add eax, 1
    mov DWORD PTR [rbp-4], eax
.L3:

In C, it seems that boolean tests of integral variables happens without the intermediate conversion to bool. Note that al is never involved, so this implies that the value is never "converted" to a one-byte bool before testing it for non-zero.

like image 99
Jonathon Reinhart Avatar answered Dec 31 '25 19:12

Jonathon Reinhart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!