What is the purpose of the EBP frame pointer register?

57,914

Solution 1

Frame pointer is a reference pointer allowing a debugger to know where local variable or an argument is at with a single constant offset. Although ESP's value changes over the course of execution, EBP remains the same making it possible to reach the same variable at the same offset (such as first parameter will always be at EBP+8 while ESP offsets can change significantly since you'll be pushing/popping things)

Why don't compilers throw away frame pointer? Because with frame pointer, the debugger can figure out where local variables and arguments are using the symbol table since they are guaranteed to be at a constant offset to EBP. Otherwise there isn't an easy way to figure where a local variable is at any point in code.

As Greg mentioned, it also helps stack unwinding for a debugger since EBP provides a reverse linked list of stack frames therefore letting the debugger to figure out size of stack frame (local variables + arguments) of the function.

Most compilers provide an option to omit frame pointers although it makes debugging really hard. That option should never be used globally, even in release code. You don't know when you'll need to debug a user's crash.

Solution 2

Just adding my two cents to already good answers.

It's part of a good language architecture to have a chain of stack frames. The BP points to the current frame, where subroutine-local variables are stored. (Locals are at negative offsets, and arguments are at positive offsets.)

The idea that it is preventing a perfectly good register from being used in optimization raises the question: when and where is optimization actually worthwhile?

Optimization is only worthwhile in tight loops that 1) do not call functions, 2) where the program counter spends a significant fraction of its time, and 3) in code the compiler actually will ever see (i.e. non-library functions). This is usually a very small fraction of the overall code, especially in large systems.

Other code can be twisted and squeezed to get rid of cycles, and it simply won't matter, because the program counter is practically never there.

I know you didn't ask this, but in my experience, 99% of performance problems have nothing at all to do with compiler optimization. They have everything to do with over-design.

Solution 3

It depends on the compiler, certainly. I've seen optimized code emitted by x86 compilers that freely uses the EBP register as a general purpose register. (I don't recall which compiler I noticed that with, though.)

Compilers may also choose to maintain the EBP register to assist with stack unwinding during exception handling, but again this depends on the precise compiler implementation.

Solution 4

However, x86 has very few registers

This is true only in the sense that opcodes can only address 8 registers. The processor itself will actually have many more registers than that and use register renaming, pipelining, speculative execution, and other processor buzzwords to get around that limit. Wikipedia has a good introductory paragraph as to what an x86 processor can do to overcome the register limit: http://en.wikipedia.org/wiki/X86#Current_implementations.

Solution 5

Using stack frames has gotten incredibly cheap in any hardware even remotely modern. If you have cheap stack frames then saving a couple of registers isn't as important. I'm sure fast stack frames vs. more registers was an engineering trade-off, and fast stack frames won.

How much are you saving going pure register? Is it worth it?

Share:
57,914

Related videos on Youtube

dsimcha
Author by

dsimcha

Updated on June 12, 2020

Comments

  • dsimcha
    dsimcha almost 4 years

    I'm a beginner in assembly language and have noticed that the x86 code emitted by compilers usually keeps the frame pointer around even in release/optimized mode when it could use the EBP register for something else.

    I understand why the frame pointer might make code easier to debug, and might be necessary if alloca() is called within a function. However, x86 has very few registers and using two of them to hold the location of the stack frame when one would suffice just doesn't make sense to me. Why is omitting the frame pointer considered a bad idea even in optimized/release builds?

    • Sedat Kapanoglu
      Sedat Kapanoglu about 15 years
      If you think x86 has very few registers you should check 6502 :)
    • legends2k
      legends2k over 9 years
    • Ciro Santilli OurBigBook.com
      Ciro Santilli OurBigBook.com almost 9 years
      C99 VLA can also benefit from it.
    • Peter Cordes
      Peter Cordes over 8 years
      Yup, even with the gcc's -fomit-frame-pointer (the default for a couple years now, since gcc 4.6), it creates a stack frame in functions that use variable-length array local variables.
    • Ciro Santilli OurBigBook.com
      Ciro Santilli OurBigBook.com over 8 years
    • Alexander Malakhov
      Alexander Malakhov over 7 years
      Doesn't the frame pointer make the stack pointer redundant?. TL;DR: 1. non-trivial stack alignment 2. stack allocation (alloca) 3. ease of runtime implementation: exceptoins handling, sandbox, GC
    • supercat
      supercat about 7 years
      @SedatKapanoglu: What do you mean? The 6502 can use any of 128 16-bit address pointers in a single instruction, and that claim isn't entirely facetious. I wrote a music player awhile ago that uses nine instructions, totaling 46 cycles, on every 76-cycle scan line. In each group of four scan lines, the 36 instructions make use of 20 different pointers. Any other CPU would have needed to spend extra instructions loading the pointers before use, but the 6502's LDA(zp),y and ADC(zp),y can each pointer, add an offset, fetch the resulting memory, and load or add it to acc, in 5 cycles.
    • phuclv
      phuclv almost 6 years
    • Peter Cordes
      Peter Cordes almost 6 years
      @陳 力: don't use code-formatting for emphasis or highlighting. Only use it for actual code like EBP, not names like "frame pointer". (And BTW, all-caps EBP is well-accepted, e.g. in Intel's manuals. It doesn't need to be in a different font to stand out as a register name. I normally use either EBP or ebp, not EBP when writing my own comments and answers. You've made a lot of edits recently, so please go back and correct any others that got approved with these formatting choices that go against SO standards.)
    • Peter Cordes
      Peter Cordes over 4 years
      related: Why is it better to use the ebp than the esp register to locate parameters on the stack? it isn't. -fomit-frame-pointer is on by default with optimization enabled.
  • Darron
    Darron about 15 years
    The original question is about generated code, which is strictly limited to the registers referenceable by opcodes.
  • Michael
    Michael about 15 years
    Yes, but this is why ommitting the frame pointer in optimized builds isn't as important nowadays.
  • flodin
    flodin about 15 years
    Also, it helps in generating a stack trace if your program crashes.
  • josesuero
    josesuero about 15 years
    Register renaming isn't quite the same thing as actually having a larger number of registers available though. There are still plenty of situations where register renaming won't help, but more "regular" registers would.
  • erikkallen
    erikkallen about 15 years
    The compiler probably knows what it does to ESP. The other points are valid, though, +1
  • sixtyfootersdude
    sixtyfootersdude almost 14 years
    Thanks @Mike, I found your answer very helpful.
  • augurar
    augurar about 10 years
    Doing away with the frame pointer also saves you a couple of instructions every function call, which is a small optimization on its own. BTW, your use of "begs the question" is incorrect; you mean "raises the question".
  • Mike Dunlavey
    Mike Dunlavey about 10 years
    @augurar: Fixed. Thanks. I'm a bit of a grammar grump myself :)
  • user3364825
    user3364825 almost 10 years
    @augurar Language evolves: "Begs the question" now just means "raises the question". Being a prescriptivist nitpicker for outdated usage adds nothing.
  • Peter Cordes
    Peter Cordes over 8 years
    Modern debuggers can do stack backtraces even in code compiled with -fomit-frame-pointer. That setting is the default in recent gcc.
  • Peter Cordes
    Peter Cordes over 8 years
    More registers is limited by instruction encoding. x86-64 uses bits in the REX prefix byte to extend the register-specifying part of instructions from 3 to 4 bits for src and dest registers. If there was room, x86-64 probably would have gone to 32 architectural registers, although saving/restoring that many on context switches starts to add up. 15 is a huge step up from 7, but 31 is a much smaller improvement in most cases. (not counting the stack pointer as general-purpose.) Making push/pop fast is great for more than just stack frames. It's not a tradeoff with # of regs, though.
  • Sedat Kapanoglu
    Sedat Kapanoglu over 8 years
    @PeterCordes only when symbols are present i presume? otherwise, how?
  • Peter Cordes
    Peter Cordes over 8 years
    @SedatKapanoglu: A data section records the necessary info: yosefk.com/blog/…
  • Sedat Kapanoglu
    Sedat Kapanoglu over 8 years
    @PeterCordes there are several gotchas with including debug info along with the binary: size overhead and less control over what's being included. the latter is mostly a problem for proprietary software developers, not gcc's problem i guess. you can also store debug files externally and match them with the binaries at debug time, but that can be cumbersome when too many versions exist.
  • Peter Cordes
    Peter Cordes over 8 years
    @SedatKapanoglu: the .eh_frame_hdr section is used for runtime exceptions, too. You'll find it (with objdump -h) in most binaries on a Linux system, It's about 16k for /bin/bash, vs. 572B for GNU /bin/true, 108k for ffmpeg. There is a gcc option to disable generating it, but it's a "normal" data section, not a debug section that strip removes by default. Otherwise you couldn't backtrace through a library function that didn't have debug symbols. That section may be bigger than the push/mov/pop instructions it replaces, but it has near zero runtime cost (e.g. uop cache).
  • Aydin K.
    Aydin K. over 7 years
    Regarding "such as first parameter will always be at EBP-4": Isn't the first parameter on EBP+8 (on x86)?
  • Peter Cordes
    Peter Cordes over 4 years
    Most compilers default to -fomit-frame-pointer when optimization is enabled. (when the ABI allows it). GCC, clang, ICC, and MSVC all do it, IIRC, even when targeting 32-bit Windows. Yup, my answer on Why is it better to use the ebp than the esp register to locate parameters on the stack? shows that even 32-bit Windows can omit the frame pointer. 32-bit x86 Linux definitely can and does. And of course 64-bit ABIs have allowed frame-pointer omission from the start.
  • Sedat Kapanoglu
    Sedat Kapanoglu almost 2 years
    @AydinK. yes, exactly. thank you for the correction.