recursionassemblyx86fibonacci

Recursive Fibonacci in Assembly


I'm attempting to implement a recursive Fibonacci program in Assembly. However, my program crashes, with an unhandled exception, and I can't seem to pick out the problem. I don't doubt that it involves my improper use of the stack, but I can't seem to point out where...

.386
.model Flat
public Fibonacci
include iosmacros.inc ;includes macros for outputting to the screen

.code
Fibonacci proc

MOV EAX, [EBP+8]
CMP EAX, 1
    JA Recurse
    MOV ECX, 1
    JMP exit

Recurse:
    DEC EAX
    MOV EDX, EAX
    PUSH EAX
    CALL Fibonacci
    ADD ESP, 4
    MOV EBX, ECX
    DEC EDX
    PUSH EDX
    CALL Fibonacci
    ADD ECX, EBX
exit:
ret
Fibonacci endp


.data


end

Also, I've pushed the number that I'm using to get the Fibonacci value to the stack in an external procedure. Any ideas where the problem might lie?


Solution

  • When you perform a call, the address of the next operation is pushed to the stack as a return value. When creating a function, it is often customary to create a "stack frame". This frame can be used to print the call stack, as well as an offset for local variables and arguments. The frame is created through two operations at the beginning of the function:

    push ebp
    mov ebp, esp
    

    At the end of the function, the call stack is removed using leave, which is equivalent to the reverse of those 2 operations. When using a stack frame, value of esp is stored into ebp, making it point to a location on the stack called the frame's base. Since, above this address, there are the old value of ebp and the return address, you would normally get the first argument using [ebp+8]. However, you did not set up a stack frame. This means that the old value of ebp was not pushed to the stack, and the current value of ebp cannot be used to get arguments because you don't know where it is. Therefore, you should get your argument using [esp+4].

    Also, it is customary that return values are placed in eax and ebx be preserved for the caller. Your code does not follow either of these conventions. Also, technically functions aren't required to preserved ecx or edx, so normally you should push them to the stack before calling another function if you want them preserved. With this code, edx and ebx would be overwritten if called with a value greater than 2, causing an invalid result.

    Here is a full listing which includes all of the fixes I have mentioned. I did not create a stack frame as it is not necessary and your code didn't.

    .386
    .model Flat
    public Fibonacci
    include iosmacros.inc ;includes macros for outputting to the screen
    
    .code
    Fibonacci proc
    
        MOV EAX, [ESP+4]
        CMP EAX, 1
        JA Recurse
        MOV EAX, 1 ; return value in eax
        JMP exit
    
    Recurse:
        PUSH EBX ; preserve value of ebx
        DEC EAX
        PUSH EAX
        CALL Fibonacci
        MOV EBX, EAX ; ebx is preserved by callee, so it is safe to use
        DEC [ESP] ; decrement the value already on the stack
        CALL Fibonacci
        ADD EAX, EBX ; return value in eax
        ADD ESP, 4 ; remove value from stack
        POP EBX ; restore old value of ebx
    exit:
    ret
    Fibonacci endp