Noahnder
Noahnder

Reputation: 425

Factorial Assembly x86

I have this assembly code(Linux 32Bit compiled with gcc -m32) and I do not really understand why my program doesn't work.

.data

    .bla:
            .ascii "%d\n\0"

    .globl main

    .text

    main:           pushl $4
                    call factorial
                    movl $1, %eax
                    ret
    factorial:
                    push %ebp
                    movl %esp, %ebp
                    movl 8(%ebp), %ecx
                    cmpl $1, %ecx
                    jg .rek
                    movl $1, %eax
                    movl %ebp, %esp
                    pop %ebp
                    ret

    .rek:
                    decl %ecx
                    pushl %ecx
                    call factorial
                    addl $4, %esp
                    movl 8(%ebp), %ecx
                    imull %ecx, %eax
                    pushl %eax
                    pushl $.bla
                    call printf
                    addl $8, %esp
                    movl %ebp, %esp
                    pop %ebp
                    ret

Unfortunately every time a Segmentation Fault does occur + parameters bigger than 4 do not work.

This should be my stack when I run the program with "3":

3
ret add
ebp
2
ret add
ebp
1
ret add
ebp

When I reach the bottom of the recursion I take the return value saved in eax and multiply it with 8(%ebp) which should be the next value.

I really appreciate any help you can provide.

Upvotes: 1

Views: 2733

Answers (1)

lurker
lurker

Reputation: 58244

Three issues I see.

1) Your call maine (I'm assuming that was a typo, and you meant, main) should be call factorial

2) In your main program, you don't restore your stack pointer.

3) Your printf call modifies %eax and overwrites the result of your factorial before it returns.

Repaired program:

.data

.bla:
        .ascii "%d\n\0"

.globl main

.text

main:   pushl $5
        call factorial
        addl $4, %esp         # ADDED THIS
        movl $1, %eax
        ret
factorial:
        push %ebp
        movl %esp, %ebp
        movl 8(%ebp), %ecx
        cmpl $1, %ecx
        jg .rek
        movl $1, %eax
        movl %ebp, %esp
        pop %ebp
        ret
.rek:
        decl %ecx
        pushl %ecx
        call factorial   # FIXED THIS
        addl $4, %esp
        movl 8(%ebp), %ecx
        imull %ecx, %eax
        pushl %eax            # ADDED THIS - SAVE RETURN VALUE
        pushl %eax
        pushl $.bla
        call printf
        addl $8, %esp         # MODIFIED THIS
        pop %eax              # ADDED THIS (restore eax result)
        movl %ebp, %esp
        pop %ebp
        ret

Upvotes: 1

Related Questions