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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 | # !> Three versions of factorial in assembly
.global main
.text
# Assembly Design Recipe
# 1. Signature / purpose
# long fact(long n)
# Computes the nth factorial
# 2. Pseudocode
# long fact(long n) {
# if (n < 2)
# return 1;
# else
# temp = fact(n - 1);
# return n * temp;
# }
# 3. Variable mappings
# n -> %rdi -> %r12
# temp -> %rax
# 4. Skeleton
# 5. Complete the body
# Version 1: callee-save register
# long fact(long n)
fact:
# PROLOGUE
pushq %r12 # push 8 bytes
enter $8, $0 # allocate 8 bytes to align the stack pointer
# BODY
# if (n < 2)
cmpq $2, %rdi
jge fact_else
# return 1;
movq $1, %rax
jmp fact_ret
fact_else:
# else {
movq %rdi, %r12
subq $1, %rdi
call fact
# temp = fact(n - 1);
# return n * temp;
imulq %r12, %rax
# EPILOGUE
fact_ret:
leave
popq %r12
ret
# }
# Version 2: Using local variables in the stack frame
# n -> %rdi -> -8(%rbp)
# temp -> %rax
fact2:
# PROLOGUE
enter $16, $0 # allocate 8 bytes + 8 bytes to align rsp
# BODY
# if (n < 2)
cmpq $2, %rdi
jge fact2_else
# return 1;
movq $1, %rax
jmp fact2_ret
fact2_else:
# else {
movq %rdi, -8(%rbp)
subq $1, %rdi
call fact2
# temp = fact2(n - 1);
# return n * temp;
imulq -8(%rbp), %rax
# EPILOGUE
fact2_ret:
leave
ret
# }
# Version 3: Using a caller-save register
# n -> %r10
fact3:
# PROLOGUE
enter $0, $0
# BODY
# if (n < 2)
cmpq $2, %rdi
jge fact3_else
# return 1;
movq $1, %rax
jmp fact3_ret
fact3_else:
# else {
movq %rdi, %r10
subq $1, %rdi
pushq %r10 # push twice to align the stack pointer
pushq %r10
call fact3
# temp = fact3(n - 1);
# return n * temp;
popq %r10
popq %r10
imulq %r10, %rax
# EPILOGUE
fact3_ret:
leave
ret
# }
# int main(int argc, char *argv[])
# tmp -> %rax
main:
enter $0, $0
# tmp = fact(5)
movq $5, %rdi
call fact3
# printf("%ld\n", tmp)
movq $format, %rdi
movq %rax, %rsi
movb $0, %al
call printf
# return 0;
movq $0, %rax
leave
ret
.data
format:
.asciz "%ld\n"
|