0

I disassembled a small program that asks the user for their name then outputs "Hello + [user's_name]"

This is the disassembled output:

Main function:

Main function

Say hello function:

Say hello function

I noticed that for the main() function, the ESP register is decremented by Ox10 and for the say_hello() function, the ESP register is decremented by Ox20. Why is this the case?

FYI: My processor is an 1.4 GHz Intel Core i5 and I'm running OSX

Original C code:

void say_hello (void);

int main (){

    printf("Enter your name\n");
    say_hello();
    return 0;
}

void say_hello (void) { 

    char name[5]; 
    gets(name); //this is a unsafe function to use. Results in stack overflow
    printf("Hello %s\n", name); 

}
SivaDotRender
  • 1,581
  • 4
  • 21
  • 37

3 Answers3

3

It allocates space on the stack for local variables. First BP it set to the current value of SP, then SP is decremented to make room for the local variables used by the function. As you can see, later [ss:rbp+???] is used to access parts of memory of this reserved space.

This is basically the same as PUSHing some dummy value a repeated number of times onto the stack.

Before the function leaves, it is crucial that the exact amount is added back to SP, otherwise a wrong return address will be used by the RET instruction, and the program will most likely crash.

Dan Byström
  • 9,067
  • 5
  • 38
  • 68
  • Right, as we can see, exactly this is happening here also. – icbytes May 06 '15 at 07:00
  • It would be good to add that you sometimes do this to align a stack. For example, the ABI requires a 16 byte aligned stack for all function calls into the system libraries. – David Hoelzer May 06 '15 at 09:49
  • That is correct, but that's not really what the OP is asking here, I think. Aligning it, probably with an AND instruction I guess, is not what's happening here. But anyone reading your comment will know about that stuff too now. :-) – Dan Byström May 06 '15 at 10:03
  • In fact I appreciate this info, I did not knew it before. "...ABI requires 16 byte aligned stack for all function calls into sys-libraries. Does this in fact mean(lets say for linux) that each system-call (lets say, execve for example), also expects stack being aligned on 16 bytes ? – icbytes May 06 '15 at 15:34
  • @DanByström If you look at the main function (I just added), I did not declare any local variables. Also where is the instruction that pushes the local variable onto the stack? Is this done automatically by the call instruction? Thanks – SivaDotRender May 06 '15 at 16:54
  • The stack space is accessed through `rbp`, as Dan already told above. – Jongware May 06 '15 at 17:24
  • @Jongware I know how its accessed. I wanted to know when its pushed onto the stack. – SivaDotRender May 06 '15 at 19:08
  • You may have read something about a stack and how it gets used with `push` and `pop`. Well, there is a bit more than that; and Dan's answer explains it quite clearly. – Jongware May 06 '15 at 19:47
  • @Jongware I understand his answer. I am asking him how the local variable got into the stack in the first place. There doesn't seem to be any explicit instruction that does this. Simply decremented the ESP resister does not mean that the local variable values are copied onto the stack. I am also wondering, if the ESP register is being decremented to reserve space for local variables, why is this still being done in the main function despite me not declaring any local variables there. I am just wondering if the even memory alignment suggestion might be what is happening here? – SivaDotRender May 06 '15 at 20:28
  • 2
    I've just looked a little more closely at the code, and I admit that there are some things I don't understand (like why the return value in rax is being saved when its never used). But you say "Simply decremented the ESP resister does not mean that the local variable values are copied onto the stack". Well, in C, local values are unassigned, so no copying has to be done. Only allocation, which decrementing ESP will do quite nicely. – Dan Byström May 06 '15 at 21:48
  • Thank you. I also read up whats called the the [red zone](http://stackoverflow.com/questions/25787408/amd64-abi-128-byte-red-zone). I believe that yours is the correct answer – SivaDotRender May 07 '15 at 16:58
2

The stack is "implemented" by means of the stack pointer, which points into the stack segment. Every time something is pushed on the stack (by means of pushl, call, or a similar stack opcode), it is written to the address the stack pointer points to, and the stack pointer decremented (stack is growing downwards, i.e. smaller addresses). When you pop something off the stack (popl, ret), the stack pointer is incremented and the value read off the stack.

For different function calls, we reserve space for local variables in the stack, so we decrement it and get the space. This is usually done using prologue and epilogue.

Prologue

A function prologue typically does the following actions if the architecture has a base pointer (also known as frame pointer) and a stack pointer (the following actions may not be applicable to those architectures that are missing a base pointer or stack pointer) :

  • Pushes the old base pointer onto the stack, such that it can be restored later (by getting the new base pointer value which is set in the next step and is always pointed to this location).
  • Assigns the value of stack pointer (which is pointed to the saved base pointer and the top of the old stack frame) into base pointer such that a new stack frame will be created on top of the old stack frame (i.e. the top of the old stack frame will become the base of the new stack frame).
  • Moves the stack pointer further by decreasing or increasing its value, depending on whether the stack grows down or up. On x86, the stack pointer is decreased to make room for variables (i.e. the function's local variables).

Epilogue

Function epilogue reverses the actions of the function prologue and returns control to the calling function. It typically does the following actions (this procedure may differ from one architecture to another):

  • Replaces the stack pointer with the current base (or frame) pointer, so the stack pointer is restored to its value before the prologue
  • Pops the base pointer off the stack, so it is restored to its value before the prologue
  • Returns to the calling function, by popping the previous frame's program counter off the stack and jumping to it
Abhineet
  • 5,320
  • 1
  • 25
  • 43
0

As far as I rememeber, such decrements are mostly used to "reserve" place on stack or to guarantee even memory alignment.

What does it mean to align the stack?

Community
  • 1
  • 1
icbytes
  • 1,831
  • 1
  • 17
  • 27
  • I think this answer makes sense. However, according to your link, memory alignment is done using an AND1 instruction. Why is it being done using a sub instruction here? – SivaDotRender May 06 '15 at 14:40
  • You remembered wrong. The decrements are there to make room for locals. `sub rsp, 0x10` decrements the stack pointer by 16. This never changes an unaligned address to an aligned address on x64. If it was unaligned prior to the subtraction, it will be unaligned still. – IInspectable Aug 17 '15 at 14:47
  • I said that. If You read properly. There is an OR in my answer, also. – icbytes Aug 17 '15 at 14:57