NONE
NONE

Reputation: 233

Fibonacci implementation in assembly giving unexpected results

I'm trying to write an assembly code version of Fibonacci which gives the nth Fibonacci number and returns it.

For some reason it is having trouble storing the return value of the Fibonacci numbers and adding them.

I want it to print the nth Fibonacci number.

I have made some modifications to my code, now it is still incorrect, but it's closer. Now it tells me that the 11th fibonacci number is 48. Still incorrect, but we're getting somewhere right?

.text

    .globl _fibonacci
_fibonacci:
    pushl %ebp
    movl %esp,%ebp
    push %esi
    movl 8(%ebp),%esi

    cmp $1,%esi
    jle BASE
    sub $1,%esi
    push %esi
    call _fibonacci
    add $4,%esp
    movl %eax,%edx
    sub $1,%esi
    push %esi
    call _fibonacci
    add $4,%esp
    add %eax,%edx
    movl %edx,%eax

DONE:
    pop %esi
    pop %ebp
    ret

BASE:
    mov $1,%eax
    jmp DONE

I'm calling this assembly code using C:

#include <stdio.h>

int fibonacci(int n);

int main(void){
  int n=111;
  int x=fibonacci(n);
  printf("The %d fibonaacci number is %d\n",n,x);
}

Upvotes: 4

Views: 4542

Answers (2)

Jeremy W. Sherman
Jeremy W. Sherman

Reputation: 36143

Your recursive calls are clobbering %edx. You need to pushl %edx in your prologue and popl %edx in your postlogue, like so:

.text

    .globl _fibonacci
/* fib(n) = fib(n-1) + fib(n-2) */
_fibonacci:
    pushl %ebp
    movl %esp,%ebp
    pushl %esi
    pushl %edx  /* <-- PUSH TO SAVE BEFORE CLOBBERING */
    movl 8(%ebp),%esi

    /* 0th and 1st numbers are defined to be 1. */
    cmpl $1,%esi
    jle BASE

    /* find fib(n-1) */
    subl $1,%esi
    pushl %esi
    call _fibonacci

    addl $4,%esp
    movl %eax,%edx  /* <-- %edx CLOBBERED! */

    /* find fib(n-2) */
    subl $1,%esi
    pushl %esi
    call _fibonacci

    addl $4,%esp
    addl %edx,%eax

DONE:
    popl %edx  /* <-- POP TO RESTORE AFTER CLOBBERING */
    popl %esi
    popl %ebp
    ret

BASE:
    movl $1,%eax
    jmp DONE

Using this driver:

// BUILD -arch i386 ONLY
// clang -arch i386 fib.s fibo.c -o fibo
#include <stdio.h>

int fibonacci(int n);

void Test(int i) {
  int r = fibonacci(i);
  printf("fib(%d) -> %d\n", i, r);
}

int main(void){
  for (int i = 0; i < 10; ++i) {
    Test(i);
  }
  return 0;
}

Test run looks like:

$ ./fibo 
fib(0) -> 1
fib(1) -> 1
fib(2) -> 2
fib(3) -> 3
fib(4) -> 5
fib(5) -> 8
fib(6) -> 13
fib(7) -> 21
fib(8) -> 34
fib(9) -> 55

Upvotes: 2

Matthew Slattery
Matthew Slattery

Reputation: 47058

The problem is that you need to be more careful with register usage across the recursive calls.

Your code assumes that %edx retains its value across the second call.

However, this is not the case, because _fibonacci changes it.

Upvotes: 1

Related Questions