Skip to main content
Engineering LibreTexts

12.8: Stack-Based Local Variables

  • Page ID
    58055
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    If local variables are required, they are allocated on the stack. By adjusting the rsp register, additional memory is allocated on the stack for locals. As such, when the function is completed, the memory used for the stack-based local variables is released (and no longer uses memory).

    Further expanding the previous example, if we assume all array values are between 0 and 99, and we wish to find the mode (number that occurs the most often), a single double-word variable count and a one hundred (100) element local double-word array, tmpArr[100] might be used.

    As before, the frame register, rbp, is pushed on the stack and set pointing to itself. The frame register plus an appropriate offset will allow accessing any arguments passed on the stack. For example, rbp+16 is the location of the first stack-based argument (7th integer argument).

    After the frame register is pushed, an adjustment to the stack pointer register, rsp, is made to allocate space for the local variables, a 100-element array in this example. Since the count variable is a one double-word, 4-bytes is needed. The temporary array is 100 double-word elements, 400 bytes is required. Thus, a total of 404 bytes is required. Since the stack is implemented growing downward in memory, the 404 bytes is subtracted from the stack pointer register.

    Then any saved registers, rbx and r12 in this example, are pushed on the stack.

    When leaving the function, the saved registers and then the locals must be cleared from the stack. The preferred method of doing this is to pop the saved registers and then top copy the rbp register into the rsp register, thus ensuring the rsp register points to the correct place on the stack.

         mov     rsp, rbp

    This is generally better than adding the offset back to the stack since allocated space may be altered as needed without also requiring adjustments to the epilogue code.

    It should be clear that variables allocated in this manner are uninitialized. Should the function require the variables to be initialized, possibly to 0, such initializations must be explicitly performed.

    For this example, the call frame would be formatted as follows:

    截屏2021-07-29 下午10.18.15.png

    The layout and order of the local variables within the allocated 404 bytes is arbitrary. For example, the updated prologue code for this expanded example would be:

        push     rbp                         ; prologue
        mov      rbp, rsp
        sub      rsp, 404                    ; allocate locals 
        push     rbx
        push     r12
    

    The local variables can be accessed relative to the frame pointer register, rbp. For example, to initialize the count variable, now allocated to rbp-404, the following instruction could be used:

        mov     dword [rbp-404], 0
    

    To access the tmpArr, the starting address must be obtained which can be performed with the lea instruction. For example,

        lea rbx, dword [rbp-400]

    Which will set the appropriate stack address in the rbx register where rbx was chosen arbitrarily. The dword qualifier in this example is not required, and may be misleading, since addresses are always 64-bits (on a 64-bit architecture). Once set as above, the tmpArr starting address in rbx is used in the usual manner.

    For example, a small incomplete function code fragment demonstrating the accessing of stack-based local variables is as follows:

        ; -----------------------------------------
        ;  Example function
    
        global  expFunc
        expFunc:
            push     rbp                            ; prologue
            mov      rbp, rsp 
            sub      rsp, 404                       ; allocate locals
            push     rbx push r12
    
    ; -----
    ;  Initialize count local variable to 0.
    
            mov      dword [rbp-404], 0
    
    ; -----
    ;  Increment count variable (for example)...
    
            inc     dword [rbp-404]                 ; count++
    
    ; -----
    ;  Loop to initialize tmpArr to all 0's.
    
            lea     rbx, dword [rbp-400]            ; tmpArr addr
            mov     r12, 0                          ; index
    zeroLoop:
            mov     dword [rbx+r12*4], 0            ; tmpArr[index]=0
            inc     r12
            cmp     r12, 100
            jl      zeroLoop
    
    ; -----
    ;  Done, restore all and return to calling routine.
    
            pop     r12                             ; epilogue 
            pop     rbx
            mov     rsp, rbp                        ; clear locals
            pop     rbp
            ret
    

    Note, this example function focuses only on how stack-based local variables are accessed and does not perform anything useful.


    12.8: Stack-Based Local Variables is shared under a not declared license and was authored, remixed, and/or curated by LibreTexts.

    • Was this article helpful?