1

I know this is a pretty basic question, but here it goes:

I am starting to learn Assembler, and I'm trying to understand how the stack works.

At first, when I pass a value to an assembler function, I'd access it like this:

movl 4(%esp),%eax  # first parameter
movl 8(%esp),%ebx  # second parameter

But I then was told that it was better to do this:

push %ebp
movl %esp,%ebp
# and then I'd access the values on %ebp:
movl 8(%ebp),%eax
movl 12(%ebp),%eax
pop %ebp

Ok, what is the difference here? When I accessed the values directly from %esp, weren't they already on the stack? What's the advantage of using push to do it again?

Does anyone have a tip on a good learning tool (for dummies-type) on how to learn how stack works so one can learn on these stack pointers, return addresses and so on? I haven't found any good visual demonstration on how it works. Thanks!

Fifoernik
  • 9,779
  • 1
  • 21
  • 27
francisaugusto
  • 1,077
  • 1
  • 12
  • 29
  • 3
    Suppose that you push something on the stack within your function. If you copy the current stack pointer to `ebp` at the beginning of the function you won't have to keep track of changes made to `esp` when you access the arguments. – Michael Feb 25 '15 at 09:39
  • Thanks, @Michael. I guess I'm just confused with what each of them (`%ebp` and `%esp`) does, and how I should keep track of the stack and addresses. – francisaugusto Feb 25 '15 at 09:59
  • 1
    By the way, the second one isn't better, unless something else forces you to set up a standard stack frame. It's clearly more instructions and you don't typically change esp after setting up the locals anyway, so esp is as stable as ebp. – Jester Feb 25 '15 at 10:03
  • 2
    you should find a lot of good sketches on the internet on how the stack works. Maybe google books can help you as well. When you want to understand what EBP is used for, you need to google for "stack frame". A Stack frame is a selfmade structure that is created "inside" of the stack. That is something, that high programming language compiler generate, when you call a function. Everytime you call a function, the compiler will create a stack frame for the called function. But when you write assembly code by yourself, you can create a stack frame by hand, if you want to. But you dont have to. – Welcor Feb 25 '15 at 11:40
  • 1
    The reason you use EBP and not ESI is because EBP by default accesses the Stack Segment, whereas ESI accesses the Data Segment. These can be overridden, but the intention is for the registers to be used in that way. – Weather Vane Feb 25 '15 at 12:18

2 Answers2

2

In most cases using %ebp has historical reasons: In 16-bit programs instructions like "movw 2(%sp), %ax" are not supported by x86 CPUs because x86 CPUs only support %bx, %si, %di and %bp registers for memory addressing. So in 16-bit programs you cannot use %sp so you use %bp instead.

When using a well-optimizing modern compiler you will not see the "push" and "mov %esp, %ebp" instructions any more in 32-bit code but the code will look like your first example ("4(%esp)" instead of "8(%ebp)").

Such compilers sometimes use the %ebp register for different purposes.

There is one use case where %ebp still is necessary: The alloca() function: This function reserves memory on the stack by doing a "sub %eax, %esp" (or similar) instruction. After this instruction you do not know any longer where your arguments are.

However in 32-bit code with "flat" memory layout (%ds=%ss) you may also use any other register instead of %ebp.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
  • Thanks @Martin. However, if I need local variables, isn't it better to use %ebp, so that I don't confuse what was once a `4(%esp)` then becomes a `8(%esp)` with the addition of something to the stack? – francisaugusto Feb 27 '15 at 15:26
  • 1
    If you manually program larger assembly code you are right. For smaller assembly code you can have an overview over all push/pop operations so you can use x(%esp) anyway. For compiled code this is not an argument because the compiler does not get "confused". – Martin Rosenau Feb 27 '15 at 16:42
1

Both the difference and the why has to do with stack frames. The following link has a fairly good summary (if I do say so myself).

What is stack frame in assembly?

Community
  • 1
  • 1
Sparky
  • 13,505
  • 4
  • 26
  • 27
  • Thanks, @Sparky. This was the best tutorial on stack so far. I didn't fully understand it now, but I understand way more. I still Don't know, though: 1 - when does things get implicitly on the stack? 2 - What's exactly the base pointer for? 3 - Since pushing `%ebp` to the stack helps to track my variables easier, should I use it on every function? – francisaugusto Feb 27 '15 at 10:35
  • @francisaugusto - The base pointer is used to mark your current stack frame. Even if you push more stuff to the stack, EBP does not change until you enter the next/previous stack frame (but ESP does). As a general rule, if your routine calls another, then use EBP and the stack frame concept. If not, it is optional. The more you get used to it, the more you will learn when you don't need it. Finally, there are usually only a few cases where you may need to worry about implicit stack pushes: these include calls, interrupts and exceptions. – Sparky Feb 27 '15 at 13:04