li tang
li tang

Reputation: 41

Can %rbp be converted to Caller-saved?

I'm a freshman to the assembly field. I'm wondering why %rbp is prescribed for callee-saved.
Because I think the frame pointer describes the beginning of the current frame, aka the caller, so the task to save this value should belong to the caller, why delay the process to the callee?
Is there something deep in this that I don't understand? Or is it just a convention? Please correct me if I am wrong.

Upvotes: 2

Views: 462

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 364338

Yes, custom calling conventions are possible (as long as you don't want to call or be called by compiler-generated code), but usually this change would be for the worse.


The major point of a frame pointer is that you set it up once for the lifetime of the function. If you had to save/restore it somewhere else around every function call, that would suck.

The other point is that you save it in a standard place in your stack frame, so backtraces can follow the linked list of saved frame pointer values that walk the stack frame. That couldn't happen if it didn't get saved to a standard place within a stack frame (relative to the return address).


You'd just pick a different register as your frame pointer (a call-preserved one in whatever calling convention you're inventing, like RBP is in the standard conventions) instead of doing mov %rbp, %r13 / call foo / mov %r13, %rbp or something around every function call. (Or just leave it in R13.) You wouldn't want to push %rbp / pop %rbp around each call either because that's even less efficient, and makes it more trouble to get stack alignment correct.

That's fine, nothing (else) is special about RBP, it just means you can't save code-size with leave if you're using a reg other than RBP as your frame pointer.

Well actually, RBP (and R13) are somewhat special from an efficiency POV: the modes with RBP as the base, like (%rbp), can only be encoded with a disp8 or disp32, not without a displacement. (That encoding actually means "no base"). So RBP is obviously a good choice for a frame pointer, less good for other uses where you might hold a pointer you want to deref with no offset.

See Why are rbp and rsp called general purpose registers? for more about that.

R13 has that same downside but wouldn't be a great choice because it would mean every access to the stack always needs a REX prefix, like 4-byte mov -4(%r13), %eax vs. 3-byte with RBP.

So yes, you can do this, but there are a lot of reasons not to.


Most functions don't need a frame pointer anyway, though; gcc -O1 and higher implies -fomit-frame-pointer, so it only uses a frame pointer at all in functions that do stuff like alloca or C99 variable-length arrays. (Or that over-align the stack, e.g. by 32 or 64 bytes.)

In that case (-fomit-frame-pointer), using some other register as a frame pointer in the few functions that use one would be less wasteful of code-size. Or an actual improvement if you used say R13 and left RBP free in a function that almost never actually referenced its own stack frame, just needed it aligned for a couple instructions.

Upvotes: 4

Related Questions