/
libmalice.asm
490 lines (343 loc) · 8.27 KB
/
libmalice.asm
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
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
; libmalice
; Code for Linux on IA-32:
%macro printstring 2
mov eax, 0x4 ; write()
mov ebx, 1 ; to stdout
mov ecx, %1 ; [string]
mov edx, %2 ; string len
int 0x80
%endmacro
extern _main
extern malloc
extern free
section .text ; start of code
global _start ; export the main function
_start:
mov [__start_esp], esp
call _main
_start_end:
mov esp, [__start_esp]
call _garbage_free_all
mov ebx, eax
mov eax, 1
int 0x80
; ALLOCATION function for new garbage memory
global _malice_alloc
_malice_alloc: ; void* maliceAlloc(int size, int sourceline)
push dword [esp+4]
call malloc
add esp, 4
test eax, eax
jne _malice_alloc_ok ; if memory allocated -> OK, return it
push _str_paragraph_2
push dword [esp+8+4]
push _str_paragraph_1
push _str_alloc_2
push dword [esp+4+16]
push _str_alloc_1
call _print_string
add esp, 4
call _print_int
add esp, 4
call _print_string
add esp, 4
call _print_string
add esp, 4
call _print_int
add esp, 4
call _print_string
add esp, 4
mov eax, 1
jmp _start_end ; poor man's exception handling
_malice_alloc_ok:
push eax
call _garbage_add ; keep track of allocated memory
add esp, 4
ret
; CHECKING function for array bounds
global _check_arr
_check_arr: ; int checkArr(int sourceline, int *array, int item)
mov eax, [esp+8] ; get array address
mov eax, [eax] ; get array size (hidden element 0)
cmp [esp+12], eax
jg _check_arr_notok ; if item > size -> Not OK
cmp [esp+12], dword 0
jle _check_arr_notok ; if item <= 0 -> Not OK
jmp _check_arr_ok
_check_arr_notok:
push _str_paragraph_2
push dword [esp+4+4]
push _str_paragraph_1
push eax
push _str_abc_2
push dword [esp+12+20]
push _str_abc_1
call _print_string
add esp, 4
call _print_int
add esp, 4
call _print_string
add esp, 4
call _print_int
add esp, 4
call _print_string
add esp, 4
call _print_int
add esp, 4
call _print_string
add esp, 4
mov eax, 1
jmp _start_end ; poor man's exception handling
_check_arr_ok:
mov eax, [esp+12]
_check_arr_end:
ret
; PRINTING procedure for CHARS (8-bit in 32-bit, LSB in Intel byte order)
global _print_char
_print_char: ; void printChar(int char)
push eax ; will be: syscall number
push ebx ; will be: stdout fd
push ecx ; will be: character start address
push edx ; will be: character counter
mov edx, 1 ; print one char
lea ecx, [esp+20] ; address of the char
mov ebx, 1 ; stdout fd
mov eax, 4 ; write()
int 0x80
pop edx
pop ecx
pop ebx
pop eax
ret
; PRINTING procedure for STRINGS (8-bit)
global _print_string
_print_string: ; void printString(char *string)
push eax ; will be: syscall number
push ebx ; will be: stdout fd
push ecx ; will be: character start address
push edx ; will be: character counter
mov eax, 0 ; prepare for holding a char
mov ecx, [esp+20] ; string start address
mov edx, -1 ; init char counter to 0
_print_string_loop:
inc edx ; char_counter++
mov al, [ecx+edx] ; check next char
cmp al, 0 ; if != '\0' continue
jne _print_string_loop
mov ebx, 1 ; stdout fd
mov eax, 4 ; write()
int 0x80
pop edx
pop ecx
pop ebx
pop eax
ret
; PRINTING procedure for INTEGERS (signed, 32-bit)
global _print_int
_print_int: ; void printInt(int num)
push eax ; will be: dividend
push ebx ; will be: divisor
push ecx ; will be: character start address
push edx ; will be: character counter
mov eax, [esp+20] ; load num
sub esp, 12 ; make space for converted integer
lea ecx, [esp+11] ; string offset counter, start at lastchar+1
; so writing ends at 10 and char 11 is reserved
mov ebx, 10 ; always divide by 10
cmp eax, dword 0 ; if the number is negative, negate
jge _print_int_loop
neg eax ; great fun at -2147483648. Overflow ftw!
_print_int_loop:
mov edx, 0
idiv ebx
add edx, 0x30
dec ecx ; write next char
mov [ecx], dl
test eax, eax
jne _print_int_loop
cmp [esp+32], dword 0 ; check for negative number
jge _print_int_end ; skip for positive
dec ecx
mov [ecx], byte '-' ; add - sign
_print_int_end:
lea edx, [esp+11]
sub edx, ecx ; number of chars
mov ebx, 1 ; stdout fd
mov eax, 4 ; write()
int 0x80 ; let the number speak
add esp, 12
pop edx
pop ecx
pop ebx
pop eax
ret
; READING function for CHARACTERS (8-bit in 32-bit, LSB in Intel byte order)
global _read_char
_read_char: ; int readChar(void)
push ebx
push ecx
push edx
sub esp, 4 ; make room for character to be read
mov edx, 1 ; number of chars
mov ecx, esp ; character buffer
mov ebx, 0 ; stdin fd
mov eax, 3 ; read()
int 0x80
cmp eax, 0
jne _read_char_ok ; No end of input -> return char
mov eax, 0 ; End of Input -> return 0
jmp _read_char_end
_read_char_ok:
mov eax, 0
mov al, [esp]
_read_char_end:
add esp, 4
pop edx
pop ecx
pop ebx
ret
; READING function for STRINGS (8-bit)
; (limited to 1023 characters, no buffer overflow protection)
global _read_string
_read_string: ; char* readString(void)
push ebx ; string size counter
push ecx ; string address
push dword -1 ; don't care about line numbers for now
push dword 1024 ; that should be enough for simple strings.
; Dynamic expansion can be done later.
call _malice_alloc
add esp, 8
mov ecx, eax
mov ebx, 0
_read_string_next_char:
call _read_char
mov [ecx+ebx], al
cmp al, 10
je _read_string_end ; Newline -> Terminate string
cmp al, 0
je _read_string_end ; End of Input -> Terminate string
inc ebx
jmp _read_string_next_char
_read_string_end:
mov [ecx+ebx], byte 0 ; terminate the string
mov eax, ecx ; return its address
pop ecx
pop ebx
ret
; READING function for INTEGERS (signed, 32-bit)
global _read_int
_read_int: ; int readInt(void)
push ebx
push ecx
push edx
push esi ; negative number info
push edi ; actual number
sub esp, 4 ; make room for character to be read
mov esi, 0 ; 0 = positive
mov edi, 0 ; start with 0
_read_int_next:
mov edx, 1 ; number of chars
mov ecx, esp ; character buffer
mov ebx, 0 ; stdin fd
mov eax, 3 ; read()
int 0x80
cmp eax, 0
je _read_int_neg ; End of input
mov eax, 0
mov al, [esp]
cmp al, '-'
jne _read_int_process_digit
mov esi, 1
jmp _read_int_next
_read_int_process_digit:
cmp al, 0x30
jb _read_int_neg ; char < '0'
cmp al, 0x39
ja _read_int_neg ; char > '9'
sub eax, 0x30
imul edi, 10 ; shift old digits
add edi, eax ; add new digit
jmp _read_int_next
_read_int_neg:
test esi, esi
jz _read_int_skip_loop
neg edi
_read_int_skip_loop: ; read and skip until newline is encountered
cmp byte [esp], 0x0a
je _read_int_end ; if newline found -> end reading
mov edx, 1 ; number of chars
mov ecx, esp ; character buffer
mov ebx, 0 ; stdin fd
mov eax, 3 ; read()
int 0x80
cmp eax, 0
je _read_int_end ; End of input -> end reading
jmp _read_int_skip_loop
_read_int_end:
mov eax, edi ; Return value: The number read
add esp, 4
pop edi
pop esi
pop edx
pop ecx
pop ebx
ret
; GARBAGE COLLECTION: Adding entry to head of single linked list
global _garbage_add
_garbage_add: ; void garbageAdd(void *addr)
push eax
push ebx
push dword 8
call malloc
add esp, 4
test eax, eax ; malloc() == 0?
jne _garbage_add_listok
push _str_gc_alloc_fail
call _print_string
add esp, 4
push dword [esp+12] ; free the address we were supposed to keep
call free ; track of so we can exit correctly
add esp, 4
mov eax, 1
jmp _start_end ; poor man's exception handling
_garbage_add_listok:
mov ebx, [esp+12]
mov [eax], ebx ; store the new entry
mov ebx, [__alloc_list]
mov [eax+4], ebx ; store the tail of the list
mov [__alloc_list], eax ; update head address
pop ebx
pop eax
ret
; GARBAGE COLLECTION: Freeing the entire linked list of garbage
global _garbage_free_all
_garbage_free_all: ; void garbageFreeAll()
push eax ; eax is destroyed by free()'s inexistent return value
push ebx
mov ebx, [__alloc_list] ; get the party started
_garbage_free_all_next:
test ebx, ebx ; next entry == 0?
je _garbage_free_all_done
push dword [ebx] ; free the user mem
call free
add esp, 4
push ebx ; free the list entry mem
mov ebx, [ebx+4] ; get address of next element
call free
add esp, 4
jmp _garbage_free_all_next
_garbage_free_all_done:
mov [__alloc_list], dword 0 ; update head address
pop ebx
pop eax
ret
section .data
__start_esp: dd 0
__alloc_list: dd 0
_str_abc_1: db "Oh no! You wanted their ",0
_str_abc_2: db " piece, but they only had ",0
_str_paragraph_1: db ". Check paragraph ",0
_str_paragraph_2: db " of the story again!",10,0
_str_alloc_1: db "Oh no! You wanted ",0
_str_alloc_2: db " many physical pieces, but they didn't have this many",0
_str_gc_alloc_fail: db "Error allocating memory for garbage tracker.",10,0