segment .data
x       dq      0
prompt: db     "Enter n: ",0
scanf_format   db    "%ld",0
printf_format  db    "fact(%ld) = %ld",0x0a,0

        segment .text
        global  main                ; let the linker know about main
        global  fact                ; tell the world about fact
        extern  scanf               ; resolve write and exit from libc
        extern  printf
main:
        push    rbp
        mov     rbp, rsp
        frame   2, 0, 3
        sub     rsp, frame_size
;
;       printf("Enter n: ");
;
        segment .text
        lea     rdi, [prompt]      ; set arg 1 for printf
        xor     eax, eax            ; 0 float parameters
        call    printf
;
;       scanf("%ls", x);
;
        lea     rdi, [scanf_format] ; set arg 1 for scanf
        lea     rsi, [x]            ; set arg 2 for scanf
        xor     eax, eax            ; set rax to 0 (2 byte instruction)
        call    scanf

;
;       printf("fact(%ld) = %ld\n",x,fact(x));
;
        mov     rdi, [x]            ; move the value of x to rdi for fact call
        call    fact
        lea     rdi, [printf_format]    ; set arg 1 for printf
        mov     rsi, [x]            ; set arg 2 for printf
        mov     rdx, rax            ; set arg 3 to be x!
        xor     eax, eax            ; set rax to 0
        call    printf

;
;       return 0
;
        xor     eax, eax            ; set rax to 0 for return value
        leave
        ret

;   long fact ( long n )
;
fact:                               ; recursive factorial function
n       equ     local1
        push    rbp
        mov     rbp, rsp
        frame   1, 1, 1             ; need 1 local variable
        sub     rsp, frame_size
;
;       if ( n < 1 ) return 1;
;
        cmp     rdi, 1              ; compare argument with 1
        jg      greater             ; if n <= 1, return 1
        mov     eax, 1              ; set return value to 1
        leave
        ret
;
;       else return fact(n-1) * n;
;
greater:
        mov     [rbp+n], rdi        ; save n
        dec     rdi                 ; call fact with n-1
        call    fact
        mov     rdi, [rsp+n]        ; restore original n
        imul    rax, rdi           ; multiply fact(n-1)*n
        leave
        ret