Search code examples
recursionassemblyarm

ARM assembly - Fibonacci Implementation: PUSH and POP not working as expected


I have written this ARM assembly code. It is supposed to put the Fibonacci sequence numbers in R4 register. I'm trying to implement this C code in a:

int fibbonacci(int n) {
   if(n == 0){
      return 0;
   } else if(n == 1) {
      return 1;
   } else {
      return (fibbonacci(n-1) + fibbonacci(n-2));
   }
}

This is the assembly code:

                    AREA |.text|, CODE, READONLY
                    EXPORT Fib
                    
Fib
            ;R0(n) - store the first n numbers in the Fibonacci sequence
            ;R1    - address of the first element in the array to store the Fibonacci sequence
            MOV      R4, #0
            MOV      R5, #0
            MOV      R6, #1

FiboR
            CMP      R0, #1
            
            PUSHEQ   {R5, R6, LR}
            BEQ      Return
            SUBS     R0, R0, #1
            BL       FiboR
            
            ADD      R4, R2, R3
            PUSH     {R4, R2, LR}
                    
Return
            POP      {R2, R3, PC}
                
            ALIGN
            END 

It is not behaving exactly like that posted C code so far because I need to keep working on it and make it return to main after it prints the first 5 numbers. However for now I need to fix something.

When my code reaches this line:

PUSH     {R4, R2, LR}

It's supposed to push values R4, R2 and LR on the stack which at that moment are: 1, 0, LR. Then the code goes down into the 'Return' subroutine in which I'm doing this:

POP      {R2, R3, PC}

So at this moment R2 should be loaded with value 1, R3 with value 0 and PC with value of LR so I return to this line:

ADD      R4, R2, R3

The code does return to the ADD line however the value of R2 is not loaded with the value 1 as I expected it to. My code stays here in an infinite loop and I keep pushing {1, 0, LR} on the stack but when I try to pop these values into R2, R3 and PC apparently they are not getting popped as I would expect them to at least value 1 does not go into R2 and R2 keeps it's value of 0 forever.

Can you please help me what am I missing here? Thank you for reading!

Edit: Changed the line: PUSH {R4, R2, LR}

to: PUSH {R3, R4, LR}

And now it works. See the accepted answer for details.


Solution

  • All instructions operating on register lists always push, pop, load, store, ... the registers in ascending order of their numbers. So even if you write {R4, R2, LR}, what is actually pushed is {R2, R4, LR}. If you want a different order, you need separate PUSH instructions.