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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# These registers are not neccesarily perserved after a function call:
# RAX RCX RDX RSI RDI R8 R9 R10 R11
# Which means that these must be perserved:
# RBX RBP R12 R13 R14 R15
# The order of arguments passed to functions is as follows:
# RDI RSI RDX RCX R8 R9
# The order of the return registers is as follows:
# RAX RDX
# Buffer for file data
.section .data
myBuffer:
.space 1
.section .text
# Print RDI as an unsigned integer following by a newline.
# Note: the function does not follow the ordinary calling convention,
# but restores all registers.
.type printNum, @function
.globl printNum
printNum:
push %rbp
movq %rsp, %rbp
# save
push %rax
push %rdi
push %rsi
push %rdx
push %rcx
push %r8
push %r9
movq %rdi, %rax # arg
movq $1, %r9 # we always print "\n"
push $10 # '\n'
.LprintNum_convertLoop:
movq $0, %rdx
movq $10, %rcx
idivq %rcx
addq $48, %rdx # '0' is 48
push %rdx
addq $1, %r9
cmpq $0, %rax
jne .LprintNum_convertLoop
.LprintNum_printLoop:
movq $1, %rax # sys_write
movq $1, %rdi # stdout
movq %rsp, %rsi # buf
movq $1, %rdx # len
syscall
addq $8, %rsp
addq $-1, %r9
jne .LprintNum_printLoop
# restore
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
movq %rbp, %rsp
pop %rbp
ret
.globl intFromString # int intFromString(char *str)
# Pre: str != 0
# Pre: all characters in the string are one of 0123456789.
.type intFromString, @function
intFromString:
xorq %rax, %rax
.LintFromString_loop:
movzx (%rdi), %rsi # Move a single character/byte %rbx and zero-extend it.
cmpq $0, %rsi # A string ends with a 0-byte.
je .LintFromString_done
movq $10, %rcx # Shift the number 1 decimal place to the left.
mulq %rcx
subq $48, %rsi # Convert from ASCII character to number. ASCII '0' has value 48. '1' is 49, etc.
addq %rsi, %rax # Add the number.
addq $1, %rdi
jmp .LintFromString_loop
.LintFromString_done:
ret
# The pointer to the string is argument RDI
# It is required that the string ends with the zero byte
.type printString, @function
.globl printString
printString:
push %r12 # Save R12
movq %rdi, %r12 # Save copy of string address
call stringLength # Get length of string in RAX
movq $1, %rdi # Select to write to stdout
movq %r12, %rsi # Use pointer at start of string
movq %rax, %rdx # Put string size in rdx
movq $1, %rax # Select sys_write
syscall # Call the function
pop %r12 # Restore R12
ret
# Requires that the file is already open, and file descriptor is passed as first
# argument.
.type printFile, @function
.globl printFile
printFile:
# The callee-saved registers
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
movq %rdi, %r10 # Save file descriptor in r10
loop:
movq %r10, %rdi # Select the file discriptor
movq $0, %rax # Select read syscall
movq $1, %rdx # Size to read from file
movq $myBuffer, %rsi # Select the buffer to store input
syscall # Read from the file
cmp $0, %rax # If rax is zero, end of file
je endPrintFile # Jump to end of program
movq $1, %rdx # Put string size in RDX
movq $myBuffer, %rsi # Use pointer at start of string
movq $1, %rdi # Select to write to stdout
movq $1, %rax # Select sys_write
syscall # Call the function
jmp loop
endPrintFile:
# The callee-saved registers
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbp
pop %rbx
ret
.type printStdin, @function
.globl printStdin
printStdin:
# The callee-saved registers
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
printStdinLoop:
movq $0, %rax # Select read syscall
movq $1, %rdx # Size to read
movq $0, %rdi # Select stdin
movq $myBuffer, %rsi # Select the buffer to store input
syscall
cmp $0, %rax # Check if there was something to be read.
je endPrintStdin # If not, jump to end
movq $1, %rdx # Put string size in rdx
movq $myBuffer, %rsi # Use pointer at start of string
movq $1, %rdi # Select to write to stdout
movq $1, %rax # Select sys_write
syscall # Call the function
jmp printStdinLoop
endPrintStdin:
# The callee-saved registers
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbp
pop %rbx
ret
.type stringLength, @function
.globl stringLength
stringLength:
movq $0, %rcx # CL will keep the current byte
movq $0, %rax # The length counter
loopStringLength:
movb (%rdi), %cl # Move the lower byte of the string into CL
cmp $0, %cl # Compare 0 with the lower byte of register C
je endStringLength # Go the end
addq $1, %rax # Add one to length
addq $1, %rdi # Go one forward in address
jmp loopStringLength# Go to start of loop
endStringLength:
ret
|