16
votes

I am currently learning assembly for Intel processors. Since the stack 'grows down', why do we have to add in order to access a specific element

[ebp + 8] ;; This will access the first param

I konw we have to skip the old ebp value and the return address and that's why we use 8 ( because each are 4 bytes long ). This is kinda strange.

Also, if ebp is a backup copy for esp, what is ebp's value in the main function Ex:

_start:

;; what's ebp value here ?

push eax
push ebx
call someFunction ;; this will create a stack frame

+-----------+
|   param1  |
+-----------+
|   param0  | <--- this is [ebp + 8] ( assuming mov ebp, esp )
+-----------+
|ret_address|
+-----------+
|    ebp    |
+-----------+ <--- esp

And also when we allocate memory for locals, we have to substract from ebp ... Please give a non-ambiguous answer. Thank you!

2
A main() function is no different from a regular function, it has a prologue too. You didn't show one in your assembly snippet, not sure why. Space for locals is created by adjusting esp, not ebp.Hans Passant
There are same questions: stackoverflow.com/questions/1395591/… , and other linked to itAbyx

2 Answers

14
votes

The initial value for %ebp is usually 0. This is so debuggers know when to end following the link chain in a backtrace.

You should think of %ebp as a reference point. For convenience, it is placed between the function arguments and local variables. That way, you access arguments with a positive offset, and variables with a negative offset, so it's easy to tell whether you are accessing a variable or an argument.

3
votes

Just as you said, the stack grows down. So, you subtract to grow the stack down for locals. You add to look back in the stack for elements stored there.