banner



What Is A Stack Pointer Register

\(\newcommand{\doubler}[1]{two#one} \newcommand{\binary}{\mathtt} \newcommand{\hex}{\mathtt} \newcommand{\octal}{\mathtt} \newcommand{\prog}{\mathtt} \newcommand{\lt}{<} \newcommand{\gt}{>} \newcommand{\amp}{&} \)

Nosotros have seen that nosotros tin can allocate memory space on the stack by subtracting the number of bytes from the stack pointer, since the stack grows toward lower retention addresses. We can then salvage values on the stack in this newly allocated memory surface area. Once we have retrieved the saved values, we deallocate the stack retentiveness expanse by but adding the number of bytes to the stack pointer.

In this section, we look at a way to use stack retentivity for local variables. We could use button and pop, but if the algorithm requires a value that is non at the tiptop of the stack, I am sure you realize that it would exist very tedious to keep track of where all the values are at each point in execution of the part.

Instead, we will create local variables on the stack in the aforementioned fashion we stored saved values there, past but subtracting the number of bytes required by each variable from the stack pointer. This does not shop whatever information in the variables, information technology merely sets aside memory that nosotros tin can use. (Perhaps you have experienced the error of forgetting to initialize a local variable in C!)

Next, we take to effigy out a mode to access the variables in this reserved data area on the stack. There are no labels in this area of memory, so we cannot directly employ a name similar we did when accessing retentivity in the .rodata segment.

A much simpler solution is to found a bespeak on the stack and use this accost to straight access values on the stack relative to this address. It may seem tempting to use the stack pointer as the reference pointer, but this creates complications if we wish to use the stack within the office.

Subsection 10.v.i The Frame Pointer

At present you know the purpose of the Frame Pointer. Each function has control over an expanse on the stack, its Stack Frame. The frame pointer register, fp, contains an address that serves every bit a reference point for the stack frame. Items that are stored in the stack frame tin exist readily accessed relative to the frame pointer using the offset forms of the str and ldr instructions. To encounter how this is washed, allow us return to the C program in List 2.15.2 and look at the compiler-generated assembly language in List 10.v.1.

                    .curvation   armv6         .file   "echoChar1.c"         .section  .rodata         .align  2 .LC0:         .ascii  "Enter one character: \000"         .marshal  2 .LC1:         .ascii  "Y'all entered: \000"         .text         .align  2         .global primary         .syntax unified         .arm         .fpu    vfp         .type   main, %function main:         @ args = 0, pretend = 0, frame = viii         @ frame_needed = 1, uses_anonymous_args = 0         push    {fp, lr}         add     fp, sp, #4      @@ fix our frame pointer         sub     sp, sp, #8      @@ allocate memory for local var         mov     r2, #21         ldr     r1, .L3         mov     r0, #1         bl      write           @@ prompt user for input         sub     r3, fp, #5      @@ compute address         mov     r2, #1          @@ one char         mov     r1, r3          @@ address for storing input char         mov     r0, #0          @@ standard in (keyboard)         bl      read         mov     r2, #13         @@ nice message to user         ldr     r1, .L3+4         mov     r0, #1         bl      write         sub     r3, fp, #5      @@ address where char was stored         mov     r2, #1         mov     r1, r3         mov     r0, #1         bl      write         mov     r3, #0         mov     r0, r3         sub     sp, fp, #4      @@ deallocate local var         @ sp needed      pop        {fp, pc} .L4:         .align  2 .L3:         .word   .LC0         .word   .LC1         .size   main, .-principal         .ident  "GCC: (Raspbian 6.three.0-xviii+rpi1) half-dozen.three.0 20170516"                  
Listing ten.5.one. Echoing single characters entered on the keyboard. (gcc asm).

You lot learned in Department 8.5 that when reading from the keyboard we need to pass an address of a memory location to the reading function. In that Section nosotros were using scanf, merely the same holds truthful for read. And then we need a local variable to hold the character. The memory for this local variable is allocated on the stack with the instruction:

sub     sp, sp, #8      @@ allocate memory for local var                

This simply moves the stack pointer eight bytes. It may seem wasteful to allocate eight bytes when merely one byte is needed for a char variable. The protocol specification, Process Call Standard for the ARM Architecture[3], provides 2 constraints on the stack pointer:

  1. The stack arrow must ever be aligned to a word (4 bytes) purlieus.

  2. The stack pointer must exist double-discussion (8 bytes) aligned at a "public interface."

"Public interface" essentially ways a global function that can exist called from anywhere in the program. For example, this role calls write and read, which are functions in the C libraries. All the functions used in this volume are public, and so always align the stack pointer on 8-byte boundaries. This precaution has no effect on operation, but not doing it has the potential of creating obscure bugs in your programme.

The location in the stack frame for storing the input character is computed relative to the frame arrow:

sub     r3, fp, #5      @@ compute address                

This instruction subtracts \(5\) from the address in the frame pointer register and stores the result in register r3, fix to be passed to the read function.

Let us switch to my associates language solution, Listing x.5.2 for further explanation of how this code works.

@ echoChar2.s @ Prompts user to enter a character and echoes it. @ 2017-09-29: Bob Plantz  @ Define my Raspberry Pi         .cpu    cortex-a53         .fpu    neon-fp-armv8         .syntax unified         @ modern syntax  @ Useful source lawmaking constants         .equ    STDIN,0         .equ    STDOUT,1         .equ    aLetter,-5         .equ    local,eight  @ Constant program data         .department  .rodata         .align  2 promptMsg:         .asciz	 "Enter ane grapheme: "         .equ    promptLngth,.-promptMsg responseMsg:         .asciz	 "You entered: "         .equ    responseLngth,.-responseMsg  @ Program code         .text         .align  ii         .global master         .type   principal, %function main:         sub     sp, sp, 8       @ space for fp, lr         str     fp, [sp, 0]     @ relieve fp         str     lr, [sp, 4]     @   and lr         add     fp, sp, 4       @ set our frame arrow         sub     sp, sp, local   @ allocate retention for local var          mov     r0, STDOUT      @ prompt user for input         ldr     r1, promptMsgAddr         mov     r2, promptLngth         bl      write          mov     r0, STDIN       @ from keyboard         add     r1, fp, aLetter @ accost of aLetter         mov     r2, ane           @ one char         bl      read          mov     r0, STDOUT      @ nice bulletin for user         ldr     r1, responseMsgAddr         mov     r2, responseLngth         bl      write          mov     r0, STDOUT      @ echo user's character         add     r1, fp, aLetter @ accost of aLetter         mov     r2, one           @ one char         bl      write          mov     r0, 0           @ return 0;         add     sp, sp, local   @ deallocate local var         ldr     fp, [sp, 0]     @ restore caller fp         ldr     lr, [sp, 4]     @       lr         add     sp, sp, eight       @   and sp         bx      lr              @ return  @ Addresses of letters         .align  2 promptMsgAddr:         .word   promptMsg responseMsgAddr:         .word   responseMsg                
Listing 10.5.2. Echoing single characters entered on the keyboard. (prog asm).

The first affair to notice is that I have defined several symbols using the .equ directive to make it easier to read the code.

.equ    STDIN,0 .equ    STDOUT,1 .equ    aLetter,-v .equ    locals,8                

STDIN and STDOUT are expert names for the keyboard and screen file numbers.

Similar the gcc compiler, I employ the byte at \(-5\) from the frame pointer as the char variable to shop the input grapheme. I know that local variables are ever at negative offsets from the frame arrow, so I define the symbolic proper noun, aLetter, as a negative value. Be careful to notice that the values of offsets for the local variables need to have into account the registers that will exist saved on the stack. These offsets are relative to the frame arrow, fp, which points to a place on the stack "below" the saved registers.

And since this is the place where I am defining the local variable start, it is a good identify to besides compute and define the amount of (properly aligned) stack infinite needed for the local variable(south). I chosen this abiding locals. Information technology is the corporeality that needs to be subtracted from sp.

I as well recognize that when I call the read function, the accost of aLetter needs to be in r1. And then instead of using r3 for the ciphering and and then moving information technology to r1, I compute information technology directly into r1:

add     r1, fp, aLetter    @ address of aLetter                

You may wonder why the addresses of the two letters are not placed in the .rodata department since they should non be inverse by the program. The answer is related to the machine code for the ldr education. All ARM instructions are 32 bits long. Part of those 32 $.25 demand to be used to define the instruction, so the infinite left for specifying the address is less than 32 bits long. The grade of the ldr instruction in this program uses pc-Relative Addressing. The number that gets stored as part of the ldr instruction is the distance, in bytes, from the location of the didactics to the location of the 32-fleck data (in this instance, an address) that the program needs. When the operating system loads a program into retentivity, nosotros take no way of knowing where the .rodata section will be located in memory relative to the .text section. So the assembler cannot compute the altitude from the ldr instruction to the location where the accost of the text string is stored. By placing this location in the .text segment (forth with the instructions) the assembler can compute the distance. We will go into more detail in Chapter 11.

Subsection x.5.2 Designing the Prologue and Epilogue

Figure 10.5.3 shows the country of our stack frame after executing the prologue instructions:

primary:         stmfd   sp!, {fp, lr}   @ save caller's info         add     fp, sp, 4       @ ready our frame pointer         add     sp, sp, locals  @ allocate retentiveness for local var                
Effigy 10.v.three. The local variable in the program from Listing 10.5.ii is allocated on the stack. Numbers on the left are offsets from the address in the frame arrow (fp) register.

To generalize:

stmfd   sp!, {<registers>}   @ salvage caller'south info add     fp, sp, <m>          @ ready our frame pointer sub     sp, sp, <n>          @ allocate retentivity for local var                

where <…> are values you demand to provide. These three instructions make up the prologue to the part:

  1. Salvage the lr (return accost) and fp (caller's frame pointer), plus whatever other regiters that demand to be saved (Table 10.i.1), on the stack. The registers are specified in the register listing, {<registers>}.

  2. Constitute the frame pointer for this function. Add \(m = 4 \times (r - one)\) to the address in the sp, where \(r\) is the number of registers saved on the stack. This ensures that the frame pointer will point to the return accost.

  3. Allocate retention on the stack for the local variables in this function. The number subtracted from the sp, \(due north\text{,}\) must run into ii criteria:

    1. \(due north \geq \) total number of bytes required past local variables.

    2. \((m + n + 4)\) is a multiple of \(8\text{.}\)

I strongly urge yous to depict pictures like Figure x.5.3 when designing your stack frame. It is the only way I am able to get all the numbers to be correct, and I have been designing stack frames for over forty years.

I mention at this point that arithmetic/logic expressions can exist used to automatically compute the values of symbols in .equ statements. I would practice this in a product environs, but such automation tends to mask the bones concepts. Helping y'all learn the basic concepts is the whole point of this volume, and then I recommend that yous avoid such automation. Some other reason for avoiding it is that when there is a mistake in the automation expressions, it is much more difficult to debug it.

At this betoken in the function, the stack frame is treated as a record (or struct in C), with the frame pointer used as the reference point. When determining the offsets from the fp to locations of local data in the stack frame, call up to accept into account the memory that is occupied past the saved register values. Thus the commencement available byte for local variables is \(-5\) from the fp. Records are discussed in more detail in Department fifteen.3.

The current location of the stack pointer is considered as the "bottom" of the stack during the balance of this role.

Later this function has performed its piece of work we deallocate the local variables area on the stack by moving the stack pointer, sp. Then we restore the annals values that were saved on the stack:

add     sp, sp, local   @ deallocate local var ldmfd   sp!, {fp, lr}   @ restore caller's info                

These 2 instructions brand upwards the epilogue of the function:

  1. Referring to Effigy x.v.4, subtracting \(n\) from the accost in the stack pointer will place information technology and so it now points at the registers we saved so they tin can be restored. At this point, the values "to a higher place" the stack arrow are considered invalid, and thus, deallocated.

  2. The second instruction pops ii values off the tiptop of the stack into:

    1. the frame pointer, and

    2. the link annals.

    This restores the calling function'due south value in the frame pointer and return address.

The country of the stack later on deallocating the local variables, simply earlier restoring register contents, is shown in Figure 10.5.iv.

Figure 10.v.iv. Local variable stack area in the program from Listing ten.5.2 before restoring the caller'due south frame pointer and the link register. Although the values in the greyness expanse may remain they are invalid; using them at this point is a programming error.

Information technology is important to understand that although you know the values above the stack pointer (the gray area in Effigy x.5.iv) are probably still in memory, attempting to access them is a violation of stack protocol.

You may wonder why my epilogue and render:

add     sp, sp, local   @ deallocate local var ldmfd   sp!, {fp, lr}   @ restore caller's info bx      lr              @ return                

differs from the epilogue and render that the compiler generated:

sub     sp, fp, #4      @@ deallocate local var ldmfd   sp!, {fp, pc}                

I believe that my style makes the prologue and epilogue more symmetrical, thus less prone to errors. In my view, that outweighs the extremely minor cost of adding ane more than teaching.

What Is A Stack Pointer Register,

Source: https://bob.cs.sonoma.edu/IntroCompOrg-RPi/sec-varstack.html

Posted by: lynchthouthe1935.blogspot.com

0 Response to "What Is A Stack Pointer Register"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel