Search code examples
c++assemblyx86-64stack-memory

Why is there no `mov %rsp, %rbp` in function prologue?


In assembly, many functions begin with the following prologue:

00000001004010e0: main(int, char**)+0    push    %rbp
00000001004010e1: main(int, char**)+1    mov     %rsp,%rbp

Some functions, like the one below, do not:

                              int MainEntry(){
                                       MainEntry():
0000000100401104: MainEntry()+0          push    %rbp
0000000100401105: MainEntry()+1          push    %rbx
0000000100401106: MainEntry()+2          sub     $0x48,%rsp
000000010040110a: MainEntry()+6          lea     0x80(%rsp),%rbp
                                        vector<int> v;
0000000100401112: MainEntry()+14         lea     -0x60(%rbp),%rax
0000000100401116: MainEntry()+18         mov     %rax,%rcx
0000000100401119: MainEntry()+21         callq   0x100401b00 <std::vector<int, std::allocator<int> >::vector()>
                                        return 0;
000000010040111e: MainEntry()+26         mov     $0x0,%ebx
0000000100401123: MainEntry()+31         lea     -0x60(%rbp),%rax
0000000100401127: MainEntry()+35         mov     %rax,%rcx
000000010040112a: MainEntry()+38         callq   0x100401b20 <std::vector<int, std::allocator<int> >::~vector()>
000000010040112f: MainEntry()+43         mov     %ebx,%eax
                                     }

Here is the C++ code that compiles into this:

int main(int c, char** args){
    MainEntry();
    return 0;
}

int MainEntry(){
    vector<int> v;
    return 0;
}

So here are my two questions:

  1. In the MainEntry function, there is a push %rbp, and then a push %rbx. Why is RBX pushed onto the stack?
  2. If I understand correctly, sub $0x48, %rsp allocates 0x48 bytes on the stack, and lea 0x80(%rsp), %rbp moves 0x80 bytes down on the stack and assigns that as the base. Where is RBP going to end up in the local stack frame and how did it get there?

Solution

    1. rbx is pushed onto the stack because the calling convention says it is preserved across calls.

    2. This function is compiled without frame pointers. rbp is just another general purpose register when compiling without frame pointers.

    About the question in the title (now improved)
    The push rsp, rbp instruction doesn't exist. push always takes one argument. Perhaps you meant to ask why rbp isn't pushed. The answer is that nothing uses it and so no instructions are required to preserve it.