Compiling the following C program with GCC 6.4.1 using -O0 and -O2 gives the following results for the main() function.
int main(int argc, char *argv[]) {
if (argc == 2) {
printf("Checking License: %s\n", argv[1]);
if (strcmp(argv[1], "AAAA-Z10N-42-OK") == 0) {
printf("Access Granted!\n");
} else {
printf("WRONG!\n");
}
} else {
printf("Usage: <key>\n");
}
return 0;
}
-O0
0x0000000000400586 <+0>: push rbp
0x0000000000400587 <+1>: mov rbp,rsp
0x000000000040058a <+4>: sub rsp,0x10
0x000000000040058e <+8>: mov DWORD PTR [rbp-0x4],edi
0x0000000000400591 <+11>: mov QWORD PTR [rbp-0x10],rsi
0x0000000000400595 <+15>: cmp DWORD PTR [rbp-0x4],0x2
0x0000000000400599 <+19>: jne 0x4005ec <main+102>
0x000000000040059b <+21>: mov rax,QWORD PTR [rbp-0x10]
0x000000000040059f <+25>: add rax,0x8
0x00000000004005a3 <+29>: mov rax,QWORD PTR [rax]
0x00000000004005a6 <+32>: mov rsi,rax
0x00000000004005a9 <+35>: mov edi,0x400690
0x00000000004005ae <+40>: mov eax,0x0
0x00000000004005b3 <+45>: call 0x400470 <printf@plt>
0x00000000004005b8 <+50>: mov rax,QWORD PTR [rbp-0x10]
0x00000000004005bc <+54>: add rax,0x8
0x00000000004005c0 <+58>: mov rax,QWORD PTR [rax]
0x00000000004005c3 <+61>: mov esi,0x4006a6
0x00000000004005c8 <+66>: mov rdi,rax
0x00000000004005cb <+69>: call 0x400480 <strcmp@plt>
0x00000000004005d0 <+74>: test eax,eax
0x00000000004005d2 <+76>: jne 0x4005e0 <main+90>
0x00000000004005d4 <+78>: mov edi,0x4006b6
0x00000000004005d9 <+83>: call 0x400460 <puts@plt>
0x00000000004005de <+88>: jmp 0x4005f6 <main+112>
0x00000000004005e0 <+90>: mov edi,0x4006c6
0x00000000004005e5 <+95>: call 0x400460 <puts@plt>
0x00000000004005ea <+100>: jmp 0x4005f6 <main+112>
0x00000000004005ec <+102>: mov edi,0x4006cd
0x00000000004005f1 <+107>: call 0x400460 <puts@plt>
0x00000000004005f6 <+112>: mov eax,0x0
0x00000000004005fb <+117>: leave
0x00000000004005fc <+118>: ret
-O2
0x0000000000400490 <+0>: cmp edi,0x2
0x0000000000400493 <+3>: push rbx
0x0000000000400494 <+4>: je 0x4004a4 <main+20>
0x0000000000400496 <+6>: mov edi,0x4006bd
0x000000000040049b <+11>: call 0x400460 <puts@plt>
0x00000000004004a0 <+16>: xor eax,eax
0x00000000004004a2 <+18>: pop rbx
0x00000000004004a3 <+19>: ret
0x00000000004004a4 <+20>: mov rbx,rsi
0x00000000004004a7 <+23>: mov rsi,QWORD PTR [rsi+0x8]
0x00000000004004ab <+27>: mov edi,0x400680
0x00000000004004b0 <+32>: xor eax,eax
0x00000000004004b2 <+34>: call 0x400470 <printf@plt>
0x00000000004004b7 <+39>: mov rdi,QWORD PTR [rbx+0x8]
0x00000000004004bb <+43>: mov esi,0x400696
0x00000000004004c0 <+48>: call 0x400480 <strcmp@plt>
0x00000000004004c5 <+53>: test eax,eax
0x00000000004004c7 <+55>: jne 0x4004d5 <main+69>
0x00000000004004c9 <+57>: mov edi,0x4006a6
0x00000000004004ce <+62>: call 0x400460 <puts@plt>
0x00000000004004d3 <+67>: jmp 0x4004a0 <main+16>
0x00000000004004d5 <+69>: mov edi,0x4006b6
0x00000000004004da <+74>: call 0x400460 <puts@plt>
0x00000000004004df <+79>: jmp 0x4004a0 <main+16>
The question, as I've stated in the title, is why is GCC clearing eax with
xor eax,eax
instead of the more explicit
mov eax,0x0
in this case. It doesn't really matter here as it is reached at most once per program execution, but let us assume this happened in a critical part of the application. Is there any reason for xoring being faster than moving zero into a register?