1
\$\begingroup\$

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)?

\$\endgroup\$
0
2
\$\begingroup\$

It looks like the compiler has allocated space for the local variable on the stack, rather than using a spare register.

You asked specifically about these lines:

    mov     #0, -4(r4) ; assign 0 to i
    add     #1, -4(r4) ; Adds one to int i

We see an unusual disassembly of -4(r4) as the destination for two instructions. This is called register indexed addressing and you can read more about it in the msp-gcc manual:

MSP430 addressing modes

Indexed. The operand is in memory at address Rn+x

Therefore the destination for these instructions is located 4 bytes before the address stored in r4. It's a bit like the equivalent in C: *(pointer - 4).

Although it is a simple program you might like to recompile with varying levels of optimisation. You should see GCC start to do interesting things like omitting the function prologue where it isn't required and perhaps using a register for the i variable.

\$\endgroup\$
2
\$\begingroup\$
                 |                |
                 |----------------|
                 |                |
       B ===>    |----------------|   ||
                 | return address |   ||
       A ===>    |----------------|   ||  Stack
                 |       i        |   ||  grows
       C ===>    |----------------|   ||  downward
                 |                |   ||
                 |----------------|   \/
                 |                |
                 |----------------|
                 |                |

When main begins executing, the hardware stack pointer, r1, points to address "A", where the return address of the function that called main resides.

r4 is being used as the stack frame pointer, and for whatever reason, the software designers chose to have this point to address "B", which was the top of the stack before the return address was pushed. This means that positive offsets will access data, etc., belonging to the caller, and negative offsets will access data local to main, including the return address. It's likely that if main were to return a value, it would be stored at address "B" (offset of 0 from r4), where it would be the last thing on the stack after main returns.

main has one local variable, i, which is allocated on the stack. Rather than pushing an initial value for i, the software simply decrements the stack pointer by 2 to create the space for it at address "C". Now, if main calls any other functions, the return address will be stored just below i on the stack. However, the offset from "B" to "C" is -4, which is why the code uses that value every time it needs to access i.

It's a little bit odd that r4 itself was not pushed onto the stack before being written to (thereby saving the previous stack frame pointer), but perhaps this is something that is done by the caller on this system.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.