I do not understand what is happening in this code. The C code is:
#include <stdio.h>
int main()
{
const int mul = 100;
int x;
printf_s("Input a number\r\n");
scanf_s("%i", &x);
printf_s("%i/%i = %i\r\n", x, mul, x / mul);
return 0;
}
I expected that the resulting assembly will be some simple shifts and add/sub operations, but there are some magic constants like 51EB851Fh
, multiplications, etc. What is happening here?
; int __cdecl main()
_main proc near
x= dword ptr -8
var_4= dword ptr -4
push ebp
mov ebp, esp
sub esp, 8
mov eax, ___security_cookie
xor eax, ebp
mov [ebp+var_4], eax
push offset Format ; "Input a number\r\n"
call ds:__imp__printf_s
lea eax, [ebp+x]
push eax
push offset aI ; "%i"
call ds:__imp__scanf_s
mov ecx, [ebp+x]
mov eax, 51EB851Fh
imul ecx
sar edx, 5
mov eax, edx
shr eax, 1Fh
add eax, edx
push eax
push 64h
push ecx
push offset aIII ; "%i/%i = %i\r\n"
call ds:__imp__printf_s
mov ecx, [ebp+var_4]
add esp, 1Ch
xor ecx, ebp ; cookie
xor eax, eax
call @__security_check_cookie@4 ; __security_check_cookie(x)
mov esp, ebp
pop ebp
retn
_main endp
The code optimization in the synthesis phase is a program transformation technique, which tries to improve the intermediate code by making it consume fewer resources (i.e. CPU, Memory) so that faster-running machine code will result.
Ideally, you should write understandable, maintainable code—without compromising performance. For this reason, compilers attempt to automatically optimize the code to improve its performance, and they've become quite sophisticated in doing so nowadays.
GCC has a range of optimization levels, plus individual options to enable or disable particular optimizations. The overall compiler optimization level is controlled by the command line option -On, where n is the required optimization level, as follows: -O0 . (default).
Compiler optimization is generally implemented using a sequence of optimizing transformations, algorithms which take a program and transform it to produce a semantically equivalent output program that uses fewer resources or executes faster.
Processors are not very good at dividing, an idiv can take between 11 and 18 cycles. As opposed to shifts and multiplies, they usually only take a single cycle.
So the optimizer replaced your division by a multiplication using fixed-point math, taking advantage of a 32-bit multiply producing a 64-bit result into edx:eax. Back-of-the-envelope: n / 100 == n * 0.32 / 32 == n * (0.32 * pow(2,32)) / 32 / pow(2,32). Those divisions are very cheap, just a right-shift. And the multiplier becomes 0.32 * pow(2,32) ~= 1374389535 == 0x51EB851F
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With