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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
%define EXIT 60
%define NULL_TERMINATOR 0
%define STDOUT 1
%define SYS_CALL 1
%define NEW_STRING 0xA
%define STDIN 0
%define SPACE 0x20
%define TAB 0x9
%define MIN '0'
%define MAX '9'
section .text
; Принимает код возврата и завершает текущий процесс
exit:
mov rax, EXIT
syscall
; Принимает указатель на нуль-терминированную строку, возвращает её длину
string_length:
xor rax, rax
.loop:
cmp byte[rdi+rax], NULL_TERMINATOR ;Проверить текущий элеме равно 0
je .end
inc rax
jmp .loop
.end:
ret
; Принимает указатель на нуль-терминированную строку, выводит её в stdout
print_string:
xor rax, rax
mov rsi, rdi
call string_length ;Узнать длину стоки
mov rdx, rax ;Указать длину на строки
mov rdi, STDOUT ;Указать на stdout
mov rax, SYS_CALL ;syscall 'write'
syscall
ret
; Принимает код символа и выводит его в stdout
print_char:
push rdi
mov rsi, rsp ;Указать на адрес символа вывода
pop rdi
mov rax,SYS_CALL ;syscall 'write'
mov rdx,1 ;Указать длину строки вывода
mov rdi,STDOUT ;Указать на stdout
syscall
ret
; Переводит строку (выводит символ с кодом 0xA)
print_newline:
mov rdi, NEW_STRING ;Указать на символ перевода строки
push rcx
call print_char ;Вывести символ 0xA
pop rcx
; Выводит беззнаковое 8-байтовое число в десятичном формате
; Совет: выделите место в стеке и храните там результаты деления
; Не забудьте перевести цифры в их ASCII коды.
print_uint:
xor rax, rax
mov r8, 10 ;Делимое
mov r9, rsp
mov rax, rdi
push 0 ;Конец строки в стек
.loop:
xor rdx, rdx
div r8 ;Получить последнее число
add rdx, 48 ;Перевод в ASCII
dec rsp
mov byte[rsp], dl ;Записать остаток деления
test rax,rax ;Проверить последнее ли число
je .end
jmp .loop
.end:
mov rdi, rsp ;Записать результат в rdi
push r9
call print_string ;Ввести результат
pop r9
mov rsp, r9
ret
; Выводит знаковое 8-байтовое число в десятичном формате
print_int:
xor rax, rax
mov rax,rdi
cmp rax,0 ;Если число > 0, сразу ввести
jl .print
jmp print_uint
.print:
push rdi
mov rdi, '-'
call print_char
pop rdi
neg rdi
jmp print_uint
; Принимает два указателя на нуль-терминированные строки, возвращает 1 если они равны, 0 иначе
string_equals:
mov rax, 1
mov r8, rdi ;Указатель на первую строку
mov r9, rsi ;Указатель на вторую строку
xor rdi, rdi
xor rsi, rsi
xor rcx, rcx
.loop:
mov dil, [r8+rcx]
mov sil, [r9+rcx]
cmp sil, dil
jne .not_equal
cmp byte dil, 0 ;Если оба символа равно 0, то оставить
je .end
inc rcx
jmp .loop
.not_equal:
xor rax,rax
.end:
ret
; Читает один символ из stdin и возвращает его. Возвращает 0 если достигнут конец потока
read_char:
xor rdi, rdi ; Указать на stdin
mov rdx, 1 ; Указать на длину строки ввода
xor rax, rax ; 'read' syscall
dec rsp
mov rsi, rsp
syscall
test rax, rax
je .zero
mov rax, [rsp]
inc rsp
ret
.zero:
xor rax, rax
inc rsp
ret
; Принимает: адрес начала буфера, размер буфера
; Читает в буфер слово из stdin, пропуская пробельные символы в начале, .
; Пробельные символы это пробел 0x20, табуляция 0x9 и перевод строки 0xA.
; Останавливается и возвращает 0 если слово слишком большое для буфера
; При успехе возвращает адрес буфера в rax, длину слова в rdx.
; При неудаче возвращает 0 в rax
; Эта функция должна дописывать к слову нуль-терминатор
read_word:
mov r8, rdi
mov r9, rsi
.skip_whitespace: ;Удаление пробелов
call read_char
cmp al, SPACE
je .skip_whitespace
cmp al, TAB
je .skip_whitespace
cmp al, NEW_STRING
xor rdx,rdx
jmp .write
.loop: ;Ввести символ
push rdx
call read_char
pop rdx
.write: ;Проверить конец строки, если нет вызывать цикл ввода символа
cmp al, NEW_STRING
je .end
cmp al, SPACE
je .end
cmp al, 4
je .end
cmp al, TAB
je .end
test al, al
je .end
inc rdx
cmp rdx, r9
jge .overflow
dec rdx
mov [r8+rdx], al
inc rdx
jmp .loop
.end: ;Сохранить результат
mov byte[r8+rdx],NULL_TERMINATOR
mov rax, r8
ret
.overflow: ;Если своло слишком большой для буфера, то прекращаем работу
xor rax, rax
ret
; Принимает указатель на строку, пытается
; прочитать из её начала беззнаковое число.
; Возвращает в rax: число, rdx : его длину в символах
; rdx = 0 если число прочитать не удалось
parse_uint:
xor rax, rax
xor r8, r8
xor r9, r9
mov r10, 10
.loop:
mov r8b, [rdi + r9]
cmp r8b, MIN
jl .end
cmp r8b, MAX
jg .end ; Проверить число ли аргумент
sub r8b, '0' ; Перевод из ASCII в число
mul r10 ; Умножаем на основу системы счисления
add rax, r8 ; добавляем цифру
inc r9 ; инкрементируем длину числа
jmp .loop
.end:
mov rdx, r9
ret
; Принимает указатель на строку, пытается
; прочитать из её начала знаковое число.
; Если есть знак, пробелы между ним и числом не разрешены.
; Возвращает в rax: число, rdx : его длину в символах (включая знак, если он был)
; rdx = 0 если число прочитать не удалось
parse_int:
cmp byte[rdi], '-' ; Проверяем отрицательное ли число
jne parse_uint ; Если нет то просто идем к фукцию parse_uint
inc rdi
call parse_uint ; Если отрицателен то парсим положительное число
neg rax ; и сделаем его отрицательным
test rdx, rdx
je .end
inc rdx ; Добавляем минус в длину строки
.end:
ret
; Принимает указатель на строку, указатель на буфер и длину буфера
; Копирует строку в буфер
; Возвращает длину строки если она умещается в буфер, иначе 0
string_copy:
xor rax, rax
xor rcx, rcx
xor r9, r9
push rdi
call string_length ;Узнать длину строки
pop rdi
cmp rax, rdx
jle .loop ;Если длина строки меньше чем длины буфера то идем в цикл
xor rax,rax
ret
.loop:
mov r9b,[rdi+rcx]
mov [rsi+rcx], r9b
inc rcx
cmp byte[rcx+rsi],0 ;Если равно 0, остановить работу
jne .loop
mov rax, rdx
ret