Recursive function definitions for Lisp compiler targeting x86_64

Viewed 47

I am writing a Lisp compiler that targets x86_64. Most types of functions have worked so far, but I have now hit a roadblock. The quintessential Lisp factorial function gives me a segmentation fault. Looking at the code it seems perfectly okay, but it is not! After using GDB to trace my code it seems that the recursive process just keeps going even once rax is 1; I traced it down to -4. Does anyone know why this is happening?

This is how I'm compiling:

clang -O0 -mstackrealign -masm=intel test.asm (This uses GAS on MacOS.)

(define (factorial x)
    (if (= x 1) 1
        (* x (factorial (- x 1)))))

(define result (factorial 5))

I included definitions for the external functions that I'm calling below.

    .global _main
    .text
_main:
    push 5  # push argument to factorial
    call factorial
    add rsp, 8  # discard 1 local argument
    mov [x + rip], rax
    mov rdi, 0
    mov rax, 0x2000001
    syscall
factorial:
    push rbp
    mov rbp, rsp
    push 1  # push argument to =
    push [rbp + 16]  # push argument to =
    call equal
    add rsp, 16  # discard 2 local arguments
    cmp rax, 1  # is true?
    je true_1  # true branch
    jmp false_2  # false branch
    true_1:
    mov rax, 1
    jmp end_3
    false_2:
    push 1  # push argument to -
    push [rbp + 16]  # push argument to -
    call minus
    add rsp, 16  # discard 2 local arguments
    push rax  # result of -
    call factorial
    add rsp, 8  # discard 1 local argument
    push rax  # result of factorial
    push [rbp + 16]  # push argument to *
    call multiply
    add rsp, 16  # discard 2 local arguments
    jmp end_3
    end_3:
    mov rsp, rbp
    pop rbp
    ret

    .data
x:
    .quad 0
.macro operator mnemonic
push rbp
mov rbp, rsp

mov rax, [rbp + 24]
\mnemonic rax, [rbp + 16]

mov rsp, rbp
pop rbp
ret
.endm

minus: operator sub
multiply: operator imul
equal:
    push rbp
    mov rbp, rsp
    mov rsi, [rbp + 16]
    cmp rsi, [rbp + 24]
    je equal_true
    mov rax, 0
    jmp equal_end
    equal_true:
        mov rax, 1
        jmp equal_end
    equal_end:
        mov rsp, rbp
        pop rbp
        ret
0 Answers
Related