-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.inc
executable file
·294 lines (251 loc) · 6.27 KB
/
lib.inc
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
section .data
symbols: db "0123456789--"
section .text
; Принимает код возврата и завершает текущий процесс
exit:
mov rax, 60
syscall
; Принимает указатель на нуль-терминированную строку, возвращает её длину
string_length: ; str_len(rdi)
xor rax, rax
.loop:
cmp byte[rdi+rax], 0
je .end
inc rax
jmp .loop
.end:
ret
; Принимает указатель на нуль-терминированную строку, выводит её в stdout
print_string:
call string_length
mov rdx, rax
mov rsi, rdi
mov rax, 1
mov rdi, 1
syscall
xor rax, rax
ret
; Переводит строку (выводит символ с кодом 0xA)
print_newline:
mov rdi, 0xA
; Принимает код символа и выводит его в stdout
print_char: ;print_char(rdi)
mov rax, 1
push rdi
mov rsi, rsp
mov rdi, 1
mov rdx, 1
syscall
pop rdi
xor rax, rax
ret
; Выводит беззнаковое 8-байтовое число в десятичном формате
; Совет: выделите место в стеке и храните там результаты деления
; Не забудьте перевести цифры в их ASCII коды.
print_uint: ;print(rdi)
mov rax, rdi
mov rsi, 10
xor r8, r8
.loop:
xor rdx, rdx
div rsi
push word[symbols+rdx]
inc r8
cmp rax, 0
jnz .loop
.readloop:
xor rdi, rdi
pop di
call print_char
sub r8, 1
cmp r8, 0
jnz .readloop
xor rax, rax
ret
; Выводит знаковое 8-байтовое число в десятичном формате
print_int: ;print_int(rdi)
mov r8, rdi
cmp r8, 0
jge .abs
neg r8
mov rdi, [symbols+10]
call print_char
.abs:
mov rdi, r8
call print_uint
xor rax, rax
ret
; Принимает два указателя на нуль-терминированные строки, возвращает 1 если они равны, 0 иначе
string_equals: ;rdi, rsi
xor rcx, rcx
xor rdx, rdx
.loop:
mov cl, [rsi]
mov dl, [rdi]
cmp cl, dl
jne .BAD
cmp cl, 0
je .end_test
inc rsi
inc rdi
jmp .loop
.end_test:
mov rax, 1
ret
.BAD:
xor rax, rax
ret
; Читает один символ из stdin и возвращает его. Возвращает 0 если достигнут конец потока
read_char:
xor rax, rax
push rax
xor rdi, rdi
mov rsi, rsp
mov rdx, 1
syscall
xor rax, rax
mov al, byte[rsp]
pop r8
ret
; Принимает: адрес начала буфера, размер буфера
; Читает в буфер слово из stdin, пропуская пробельные символы в начале, .
; Пробельные символы это пробел 0x20, табуляция 0x9 и перевод строки 0xA.
; Останавливается и возвращает 0 если слово слишком большое для буфера
; При успехе возвращает адрес буфера в rax, длину слова в rdx.
; При неудаче возвращает 0 в rax
; Эта функция должна дописывать к слову нуль-терминатор
read_word: ;rdi, rsi
push r12 ;will use as counter
push r13 ;will use as link to buffer
push r14; will use as size of buffer
xor r12, r12
mov r13, rdi
mov r14, rsi
.A:
call read_char
cmp al, 0x20
je .A
cmp al, 0x9
je .A
cmp al, 0xA
je .A
cmp al, 0
je .END
jmp .B
.B:
mov byte[r13+r12], al
inc r12
call read_char
cmp al, 0x20
je .END
cmp al, 0x9
je .END
cmp al, 0xA
je .END
cmp al, 0
je .END
cmp r12, r14
je .ERROR
jmp .B
ret
.END:
mov byte[r13+r12], 0
mov rax, r13
mov rdx, r12
pop r14
pop r13
pop r12
ret
.ERROR:
pop r14
pop r13
pop r12
xor rax, rax
ret
; Принимает указатель на строку, пытается
; прочитать из её начала беззнаковое число.
; Возвращает в rax: число, rdx : его длину в символах
; rdx = 0 если число прочитать не удалось
parse_uint: ;rdi
xor rax, rax
xor rcx, rcx
.A:
mov cl, [rdi]
inc rdi
cmp cl, '0'
jb .ERR
cmp cl, '9'
ja .ERR
;; a -> b
mov r8, 1
sub cl, '0'
mov rax, rcx
jmp .B
.B:
mov cl, [rdi]
inc rdi
cmp cl, '0'
jb .OK
cmp cl, '9'
ja .OK
inc r8
mov r10, 10
mul r10 ;; result = rdx:rax
sub cl, '0'
add rax, rcx
jmp .B
.OK:
mov rdx, r8
ret
.ERR:
xor rdx, rdx
ret
; Принимает указатель на строку, пытается
; прочитать из её начала знаковое число.
; Если есть знак, пробелы между ним и числом не разрешены.
; Возвращает в rax: число, rdx : его длину в символах (включая знак, если он был)
; rdx = 0 если число прочитать не удалось
parse_int:; rdi
push r12
xor r12, r12
xor rcx, rcx
mov cl, [rdi]
cmp cl, '-'
jne .PARSE_NUMS
mov r12, 1
inc rdi
.PARSE_NUMS:
call parse_uint
cmp rdx, 0
je .ERR
cmp r12, 1
jne .OK
inc rdx
neg rax
.OK:
pop r12
ret
.ERR:
pop r12
xor rdx, rdx
ret
; Принимает указатель на строку, указатель на буфер и длину буфера
; Копирует строку в буфер
; Возвращает длину строки если она умещается в буфер, иначе 0
string_copy: ;rdi, rsi, rdx
call string_length ;rax => str_len
cmp rax, rdx
jae .finale
xor rcx, rcx
.loop:
mov cl, [rdi]
mov [rsi], cl
sub rdx, 1
inc rsi
inc rdi
test rdx, rdx
jnz .loop
ret
.finale:
mov rax, 0
ret