UserMoon
UserMoon

Reputation: 75

Need help in understanding basic Assembly code which was generated from C code

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

Answers (1)

Jonathon Reinhart
Jonathon Reinhart

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

Related Questions