# Recursion example - calculates the factorial of a number # Everything goes in the stack, no data section needed .section .data .section .text .globl _start # This is pointless unless we are exporting this function to other programs or # files. It's just here for completeness. .global factorial _start: pushq $4 # Push argument call factorial # call command pushes the next instruction's address on # the stack, when we return to it, it will pop the # address off of the stack and point the Instruction # pointer to it addq $8, %rsp # Cleanup stack - Remove the argument from it # Remember by cleanup, we just move the stackpointer # back a word (8 bytes in x86_64) times the number of # arguments pushed in the stack. movq %rax, %rdi # Move result into exit() argument register %rdi # Return values are always stored in %rax... movq $60, %rax # Setup %rax to exit() syscall number syscall # Invoke kernel's syscall # Tell linker this is a function # Export factorial as a function .type factorial, @function factorial: # Create the stack frame for this function... pushq %rbp # Save %rbp in the stack movq %rsp, %rbp # And current stack pointer in %rbp movq 16(%rbp), %rax # Retrieve argument from stack, remember, we're # dealing with quad words, %rbp is at the # beginning of the function's stack frame, # 8(%rbp) is the function's return address setup # by call command and # 16(%rbp) is our argument pushed in the stack # by the function's caller cmpq $1, %rax # If we are at 1, nothing to be done... je end_factorial decq %rax # Otherwise we decrease our current operand pushq %rax # and send it again to factorial function call factorial # here... movq 16(%rbp), %r8 # Retrieve our current argument again imulq %r8, %rax # and multiply it by the result of the factorial # below (num factorial = num * factorial of # previous num, ex. 4! == 4 * 3!) end_factorial: ## Clean up function's stack frame ## movq %rbp, %rsp # We are done with this factorial, restore popq %rbp # %rsp and %rbp and ret # return to the caller