Reputation: 75
I am learning Assembly and I am tring to understand how Assembly is being generated from C code.
I created following dummy C code:
#include <stdio.h>
int add(int x, int y){
int result = x + y;
return result;
}
int main(int argc, char *argv[]){
int x = 1 * 10;
int y = 2 * 5;
int firstArg = x + y;
int secondArg = firstArg / 2;
int value;
value = add(firstArg, secondArg);
return value;
}
And got following Assembly code
.file "first.c"
.text
.globl add
.type add, @function
add:
.LFB39:
.cfi_startproc
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
.cfi_endproc
.LFE39:
.size add, .-add
.globl main
.type main, @function
main:
.LFB40:
.cfi_startproc
movl $30, %eax
ret
.cfi_endproc
.LFE40:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
And I was very surprised where are all those arithmetic operations in main vanished? I do not understand how we got $30 from a nowhere (well, I suppose it is a return value from add function, but why I do not see any command that gets this value, actually I see that return value was already pushed to eax in the add function, so why would we need to move $30 to eax again?). Where are all local main vars are being declared? I specially created 5 of them to see how one is pushed onto the stack.
Can you also help me to understand what are all those .LFE39 .LFB40: .LFB39: mean?
I am ready the book, but it does not clarify this case for me. Actually book says that all function must begin with stack initialization:
pushl %ebp
movl %esp, %ebp
As well as when function ends it needs to complete it with pop instruction.
Which is not the case in the above code. I do not see any stack initialization.
Thank you!
Upvotes: 3
Views: 250
Reputation: 137398
You are compiling with optimizations enabled. GCC was smart enough to perform all of those calculations at compile-time, and replace all of that useless code with a simple constant.
First of all, x
and y
will get replaced with their constant expressions:
int x = 10;
int y = 10;
Then, the places where those variables are used will instead get their constant values:
int firstArg = 20;
int secondArg = 10;
Next, your add
function is small and trivial, so it will certainly get inlined:
value = firstArg + secondArg;
Now those are constants too, so the whole thing will be replaced with:
int main(int argc, char *argv[]) {
return 30;
}
While most functions will have a prologue like you've shown, your program does nothing but return 30. More specifically, it no longer uses any local variables, and calls no other functions. Because of this main
does not need a frame or reserved space on the call stack. So there's no need for the compiler to emit a prologue/epilogue.
main:
movl $30, %eax
ret
These are the only two instructions your program will run (other than the C-runtime startup code).
Further note, that because your add
function was not marked static
, the compiler had to assume that someone externally might call it. For that reason, we still see add
in the generated assembly, even though no one is calling it:
add:
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
Upvotes: 12