how to reference local variables on the stack properly

Bulat M.

Enter in function, standard prologue

push rbp
mov rbp, rsp
sub rsp, 128 ; large space for storing doubles, for example

How to reference local variables now, via rsp + positive offset, or via rbp + negative offset?

Reading https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames, indeed quite understandable. It writes

...the value of esp cannot be reliably used to determine (using the appropriate offset) the memory location of a specific local variable. To solve this problem, many compilers access local variables using negative offsets from the ebp registers.

Why not reliable? Until that question I was accessing local variables via rsp, like this:

mov rax, [rsp+.length] ; get length of array
mov [rsp+8], rax ; store sum at the stack

everything goes quite nicely using rsp for stack referencing.

Peter Cordes

Look at gcc output. It defaults to -fomit-frame-pointer when optimizing, only making a stack frame when functions use variable-length arrays or it needs to align the stack to more than 16B.

That wiki page is basically wrong. There's no scary weird stuff that makes it "unreliable". The only time you can't do it is when you need to modify RSP by an amount that isn't an assemble-time constant.


However, if you do make a stack frame with push rbp / mov rbp, rsp, you should use RBP-relative addressing modes. It's more efficient, because [rsp + 8] takes an extra byte to encode (vs. [rbp - 8]). Addressing modes with RSP as the base register always need a SIB byte, even when there's no index register.

The point of using RSP-relative addressing modes is that you can avoid wasting instructions making a stack frame, so RBP is just another call-saved register (like RBX) that you can save/restore and use for whatever you want.


The other big advantage to RBP-relative addressing is that the offset from RBP to a given variable stays constant for the entire function. Unlike compilers, we puny humans are easily confused by pushes and pops which change RSP inside a function. Of course, 64-bit code hardly ever changes RSP inside a function between the prologue and epilogue, because both ABIs pass args in registers. Saving/restoring some call-preserved registers (like RBX or R12-R15) in the prologue/epilogue is often better than having push/pop inside the function (and definitely better than inside a loop). When you need to spill/reload, mov for random access is usually best.

In 32-bit code, making a stack frame in hand-written code often makes more sense, esp. for maintainability. In 64-bit code, it's usually not much of an issue. Although saving/restoring an extra register with an extra pair of push/pop does change the stack layout, which does matter if any args were passed on the stack (e.g. a large struct by value, but write your function to take a const-pointer arg instead!).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How do local variables get stored in stack?

From Dev

How does gcc push local variables on to the stack?

From Dev

Local variables on stack

From Dev

Local variables: are they always on the stack?

From Dev

PDB: How to inspect local variables of functions in nested stack frames?

From Dev

How can I extract local variables from a stack trace?

From Dev

How to insist a C compiler put local variables on the stack, not in registers

From Dev

How does initialization of local variables (large arrays) affect stack size?

From Dev

Examining local variables up the stack

From Dev

Compiling local variables for a stack machine

From Dev

Stack overflow from local variables?

From Dev

Compiling local variables for a stack machine

From Dev

Examining local variables up the stack

From Dev

how variables are stored on stack?

From Dev

how variables are stored on stack?

From Dev

How to properly deal with a callback stack

From Dev

How to properly plot variables

From Dev

What is the idea behind using a stack for local variables?

From Dev

why preserve stack space for local variables?

From Dev

why preserve stack space for local variables?

From Dev

Linux process stack overrun by local variables (stack guarding)

From Dev

How Windows thread stack guard page mechanism works in case of uninitialized local variables?

From Dev

How Windows thread stack guard page mechanism works in case of uninitialized local variables?

From Dev

Rvalue reference and auto&& local variables

From Dev

Do local reference variables add to the GC

From Dev

C++ having reference for local variables

From Dev

How is it known that variables are in registers, or on stack?

From Dev

How to properly dispose of ThreadLocal variables?

From Dev

how to properly set environment variables

Related Related

  1. 1

    How do local variables get stored in stack?

  2. 2

    How does gcc push local variables on to the stack?

  3. 3

    Local variables on stack

  4. 4

    Local variables: are they always on the stack?

  5. 5

    PDB: How to inspect local variables of functions in nested stack frames?

  6. 6

    How can I extract local variables from a stack trace?

  7. 7

    How to insist a C compiler put local variables on the stack, not in registers

  8. 8

    How does initialization of local variables (large arrays) affect stack size?

  9. 9

    Examining local variables up the stack

  10. 10

    Compiling local variables for a stack machine

  11. 11

    Stack overflow from local variables?

  12. 12

    Compiling local variables for a stack machine

  13. 13

    Examining local variables up the stack

  14. 14

    how variables are stored on stack?

  15. 15

    how variables are stored on stack?

  16. 16

    How to properly deal with a callback stack

  17. 17

    How to properly plot variables

  18. 18

    What is the idea behind using a stack for local variables?

  19. 19

    why preserve stack space for local variables?

  20. 20

    why preserve stack space for local variables?

  21. 21

    Linux process stack overrun by local variables (stack guarding)

  22. 22

    How Windows thread stack guard page mechanism works in case of uninitialized local variables?

  23. 23

    How Windows thread stack guard page mechanism works in case of uninitialized local variables?

  24. 24

    Rvalue reference and auto&& local variables

  25. 25

    Do local reference variables add to the GC

  26. 26

    C++ having reference for local variables

  27. 27

    How is it known that variables are in registers, or on stack?

  28. 28

    How to properly dispose of ThreadLocal variables?

  29. 29

    how to properly set environment variables

HotTag

Archive