MSP430 Assembly Stack Pointer Behavior

纵然是瞬间 提交于 2020-01-23 12:37:26

问题


While trying to analyze a simple Assembly file generated through the msp430-gcc, I stumbled upon a set of instructions that I don't understand dealing with the frame pointer and the MSP430's stack pointer.

C Program:

#include "msp430g2553.h"

int main()
{
  int i;

  for(i = 0; i < 3; i++);

}

Assembly minus directives:

main:
        mov     r1, r4 ;Stores address of stack pointer in r4(frame pointer)
        add     #2, r4 ; ?
        sub     #2, r1 ; subtract 2 to allocate int i
        mov     #0, -4(r4) ; assign 0 to i
        jmp     .L2 ; start loop
.L3:
        add     #1, -4(r4) ; Adds one to int i
.L2:
        cmp     #3, -4(r4) ; Compare to #3
        jl      .L3 ; jump to .L3 if true
        add     #2, r1 ; deallocate int i
.Lfe1:
        .size   main,.Lfe1-main

I tried commenting the code to trace the program's execution, but I don't understand the line add #2, r4. What exactly is happening here, and why is int i being referenced at -4(r4)?


回答1:


Normally the first thing you'll do in a function is:

push r4

to save the current frame pointer on the stack, so you can set a new frame pointer for the function you're about to call, and then restore the old one afterwards. push will automatically decrement the stack pointer by 2, so when you then do:

mov r1, r4

the address pushed on to r4 will be above the value you just pushed on the stack ("above" here in the sense that the stack grows downwards - it's actually below in terms of numeric memory addresses). You'll want the frame pointer to actually point below the value you just pushed onto the stack, so you increment it by two to achieve this with:

add #2, r4

Because main() is the first function executed, you don't have an existing frame pointer to save, so what you're seeing here is the mov and the add in the absence of the push.

It'll make more sense when you make an actual function call, and you'll see the whole thing:

push r4
mov  r1, r4
add  #2, r4

After you've done this, -2(r4) will refer to the previous value of the frame pointer that you just pushed onto the stack, and since you haven't added two to the value of the stack pointer, -2(r4) will equal that, too.

When you now allocate 16 bits for your local variable i, you'll have to subtract 2 from the stack pointer to make room for it, and the address of i will therefore be -4(r4).

Example

As an example, suppose the stack pointer contains 0x200 and the frame pointer contains 0x202, and you then want to call a function. You start off with a stack like this:

      r4 --> 0x202    ---------------------
                             <empty>
      r1 --> 0x200    ---------------------

After you return from your function, you're going to want to restore the current value of the frame pointer, so the first thing you do is push it onto the stack to save it. After push r4, the value 0x202 therefore gets pushed onto memory location 0x200 (i.e. the top of the stack pointed to by r1), and the stack pointer gets decremented by 2 to make room for it, so you get:

      r4 --> 0x202    ---------------------
                             <empty>
             0x200    ---------------------
                              0x202
      r1 --> 0x1FE    ---------------------

Having pushed the previous value of the frame pointer onto the stack, you now want to set the current value of the frame pointer to the base of your current stack frame, so you start this off by moving the new stack pointer into r4, and you get:

             0x202    ---------------------
                             <empty>
             0x200    ---------------------
                              0x202
r1 == r4 --> 0x1FE    ---------------------

The old value of the frame pointer is the first thing in your current stack frame, so you want r4 to point before that, not after it. To do this you add 2 to r4, and you get:

             0x202    ---------------------
                              <empty>
      r4 --> 0x200    ---------------------
                               0x202
      r1 --> 0x1FE    ---------------------

The position you're in now is that r4 points to the bottom of your stack frame, and r1 points to the top of it, which is where you want to be. The only thing actually in your current stack frame at this point is the previous value of the frame pointer that you pushed onto it at the start of the function.

Then you decrement the stack pointer by 2 to make room for your new local variable, and you end up with:

             0x202    ---------------------
                             <empty>
      r4 --> 0x200    ---------------------
                              0x202
             0x1FE    ---------------------
                        <uninitialized i>
      r1 --> 0x1FC    ---------------------

and you can see that i is stored at 0x1FC, which is -4(r4). Once again you're in the position where r4 points to the bottom of your stack frame, and r1 points to the top of it, but now you have two 16 bit values in your current stack frame, so the two pointers are 4 bytes apart.

When you're ready to return at the end of your function, you'll add #2, r1 to "deallocate" the memory for your local variable i. This will give you:

             0x202    ---------------------
                              <empty>
      r4 --> 0x200    ---------------------
                               0x202
      r1 --> 0x1FE    ---------------------

You'll then pop r4, which will pop the last value off the stack (which is now 0x202, the original value of the frame pointer), put it into r4, and increment the stack pointer by 2 to reflect that that value has been removed from the stack, which will leave you at:

      r4 --> 0x202    ---------------------
                             <empty>
      r1 --> 0x200    ---------------------

which is right where you started, and you've cleaned up the stack perfectly after your function call.

Note this is slightly simplified since when you do make a function call, the program counter is also going to get pushed onto the stack, and then popped and restored again when you return, and the above example doesn't show that, but exactly the same kind of thing is going on there.



来源:https://stackoverflow.com/questions/26374287/msp430-assembly-stack-pointer-behavior

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!