Richard Richard -4 years ago 110
C Question

Why asm generated by gcc mov twice?

Suppose I have the following C code:

int main()
int x = 11;
int y = x + 3;
printf("%d\n", x);
return 0;

Then I compile it into asm using gcc, I get this(with some flag removed):

pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $11, -4(%rbp)
movl -4(%rbp), %eax
addl $3, %eax
movl %eax, -8(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax

My problem is why it is
movl -4(%rbp), %eax
followed by
movl %eax, %esi
, rather than a simple
movl -4(%rbp), %esi
(which works well according to my experiment)?

Answer Source

You probably did not enable optimizations.

Without optimization the compiler will produce code like this. For one it does not allocate data to registers, but on the stack. This means that when you operate on variables they will first be transferred to a register and then operated on.

So given that x lives is allocated in -4(%rbp) and this is what the code appears as if you translate it directly without optimization. First you move 11 to the storage of x. This means:

movl    $11, -4(%rbp)

done with the first statement. The next statement is to evaluate x+3 and place in the storage of y (which is -8(%rbp), this is done without regard of the previous generated code:

movl     -4(%rbp), %eax
addl     $3, %eax
movl     %eax, -8(%rbp)

done with the second statement. By the way that is divided into two parts: evaluation of x+3 and the storage of the result. Then the compiler continues to generate code for the printf statement, again without taking earlier statements into account.

If you on the other hand would enable optimization the compiler does a number of smart and to humans obvious things. One thing is that it allows variables to be allocated to registers, or at least keep track on where one can find the value of the variable. In this case the compiler would for example know in the second statement that x is not only stored at -4(%ebp) it will also know that it is stored in $11 (yes it nows it's actual value). It can then use this to add 3 to it which means it knows the result to be 14 (but it's smarter that that - it has also seen that you didn't use that variable so it skips that statement entirely). Next statement is the printf statement and here it can use the fact that it knows x to be 11 and pass that directly to printf. By the way it also realizes that it doesn't get to use the storage of x at -4(%ebp). Finally it may know what printf does (since you included stdio.h) so can analyze the format string and do the conversion at compile time to replace the printf statement to a call that directly writes 14 to standard out.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download