summaryrefslogtreecommitdiff
path: root/PGU/CHAP4/factorial.s
blob: d4907b70ffa7bbd588abea866f241e090ab21b2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 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