-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmacros.inc
More file actions
502 lines (445 loc) · 11 KB
/
macros.inc
File metadata and controls
502 lines (445 loc) · 11 KB
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
491
492
493
494
495
496
497
498
499
500
501
502
; MACROS FOR EASY ASSEMBLY PROGRAMMING
%ifndef MACROS_INC
%define MACROS_INC
; Ensure this file is only included once
; -- FUNCTIONS --
; -- very cool macro :3
%macro func 1 ; ADD MULTI-PARAM FUNCTIONS. USE RUN MACRO TO RUN WITH PARAMS
; just to make it more readable
%ifidn %1, main():
section .text
global _start
_start:
%elifidn %1, main
section .text
global _start
_start:
%else
section .text
global %1
%1:
%endif
%endmacro
; -- Loops --
%macro for 2
; Usage: for <varname>, <count>
pusha ; save registers :3
new dword, %1, 0 ; loop var
mov ecx, %2 ; iter count
xor eax, eax ; clear eax for the loop start
mov [%1], eax ; init loop
%1_loop:
%endmacro
%macro while 3
; Usage: while <varname>, mode (>, <, ==), <value>
new dword, %1, 0
pusha
%1_loop:
mov eax, [%1]
cmp eax, %3
; default to ==
%ifidni %2, >
jle %1_loop_end
%elifidni %2, <
jge %1_loop_end
%else
jne %1_loop_end
%endif
%endmacro
%macro break 1
jmp %1_loop_end
%endmacro
%macro end 0-2
; Usage: end <loopType>, <varname> OR `end` to end a function
; loopType is either 'for' or 'while'
%if %0 = 2
%ifidni %1, for
inc eax
mov [%2], eax
dec ecx
jnz %2_loop
popa ; YIPPIE RESTORE REGISTERS
%elifidni %1, while
inc eax
mov [%2], eax
jmp %2_loop
%2_loop_end:
popa
%else
%error "Unknown loop type for 'end' macro. Use 'for' or 'while'."
%endif
%elif %0 = 0
; func end
ret
%else
%error "Too many parameters for 'end' macro"
%endif
%endmacro
; -- INTERNAL MACROS (For internal use mainly) --
%macro escapeString 1
; literally just escapes a string :sob:
%define _s %1
%assign i 1
%strlen len _s
%rep len
%substr ch _s i 1
%ifidni ch, "\" ; handle escapes
%assign i i+1
%substr esc _s i 1
%ifidni esc, "n"
db 10
%elifidni esc, "t"
db 9
%elifidni esc, "\"
db 92
%else
db "\", esc
%endif
%else
db ch
%endif
%assign i i+1
%endrep
%endmacro
; -- DECLARATIONS --
%macro new 1-* ; add class support later
; usage:
; new string myStr, "hello", " ", "world", NEWLINE
; new byte myByte, 1, 2, 3
; new word myWord, 1234
; new dword myDword, 0xDEADBEEF
; new qword myQword, 0x1122334455667788
; new int myInt, 42 ; (the answer of life >:3)
%push
%define switchback 0
%ifnidni __SECT__, .data
section .data
%define switchback 1
%endif
; ---------- string ----------
%ifidn %1, string
%if %0 >= 3
%2:
%ifstr %3
escapeString %3
%else
db %3
%endif
%rotate 3
%rep %0-3
%ifstr %1
escapeString %1
%else
db %1
%endif
%rotate 1
%endrep
%2_len equ $ - %2
%else
%error "Not enough parameters for 'new string'"
%endif
%endif
; ---------- byte ----------
%ifidn %1, byte
%if %0 >= 3
%2: db %3
%rotate 3
%rep %0-3
db %1
%rotate 1
%endrep
%2_len equ ($ - %2) / 1
%else
%error "Not enough parameters for 'new byte'"
%endif
%endif
; ---------- word ----------
%ifidn %1, word
%if %0 >= 3
%2: dw %3
%rotate 3
%rep %0-3
dw %1
%rotate 1
%endrep
%2_len equ ($ - %2) / 2
%else
%error "Not enough parameters for 'new word'"
%endif
%endif
; ---------- dword ----------
%ifidn %1, dword
%if %0 >= 3
%2: dd %3
%rotate 3
%rep %0-3
dd %1
%rotate 1
%endrep
%2_len equ ($ - %2) / 4
%else
%error "Not enough parameters for 'new dword'"
%endif
%endif
; ---------- qword ----------
%ifidn %1, qword
%if %0 >= 3
%2: dq %3
%rotate 3
%rep %0-3
dq %1
%rotate 1
%endrep
%2_len equ ($ - %2) / 8
%else
%error "Not enough parameters for 'new qword'"
%endif
%endif
; ---------- int ----------
%ifidn %1, int
%if %0 >= 3
%2: dd %3
%rotate 3
%rep %0-3
dd %1
%rotate 1
%endrep
%2_len equ ($ - %2) / 4
%else
%error "Not enough parameters for 'new int'"
%endif
%endif
%pop
%if switchback
section .text
%endif
%endmacro
; -- UTILITY MACROS --
; --- Print macro ---
%macro print 1-*
pusha
%assign __i 1
%rep %0
%ifstr %1
jmp %%after%+__i
%%str%+__i:
escapeString %1
%%str%+__i_len equ $ - %%str%+__i
%%after%+__i:
mov eax, 4
mov ebx, 1
mov ecx, %%str%+__i
mov edx, %%str%+__i_len
int 80h
%elifnum %1
mov eax, 4
mov ebx, 1
mov ecx, %%byte%+__i
mov edx, 1
int 80h
jmp %%done%+__i
%%byte%+__i: db %1
%%done%+__i:
%else
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %1_len
int 80h
%endif
%rotate 1
%assign __i __i+1
%endrep
popa
%endmacro
; -- random number gen --
%macro random 2
; Usage: random <outputVar> <maxValue>
; Generates a random integer in [0, maxValue] inclusive.
%if %2 < 0
%error "Max value must be non-negative"
%endif
rdtsc
mov [%1], eax ; store lower 32 bits of timestamp as seed
%define LCG_MULTIPLIER 1103515245
%define LCG_INCREMENT 12345
%define LCG_MODULUS 0x80000000 ; 2^31 (for 32-bit unsigned)
mov eax, [%1] ; load seed
imul eax, LCG_MULTIPLIER
add eax, LCG_INCREMENT
and eax, LCG_MODULUS - 1 ; mod
%if %2 = 0
mov [%1], eax ; just use the random value directly
%else
%assign maxPlusOne %2 + 1
mov ecx, maxPlusOne
xor edx, edx
div ecx
mov [%1], edx ; store (random % (maxValue+1)) into outputvar
%endif
%endmacro
%macro argv 2
; Usage: argv <storeIndex>, <index>
; Loads the pointer to argv[<index>] into eax and stores it in <storeIndex>.
; Note: index starts from 0.
%if %2 < 0
%error "Index must be above 0"
%endif
mov eax, [esp + 4 + (%2) * 4] ; esp+4 for argv[0], esp+8 for argv[1], etc.
mov [%1], eax
%endmacro
; Reserve space on stack
%macro reserve 2
; Usage: reserve <bufname>, <numBytes>
section .bss
%1 resb %2
section .text
%endmacro
; -- Print C-style string macro --
%macro printC 1
pusha
mov eax, [%1]
test eax, eax
jz %%done
mov ecx, eax ; pointer to string
mov edx, 0
%%find_len:
cmp byte [ecx+edx], 0
je %%got_len
inc edx
jmp %%find_len
%%got_len:
mov eax, 4
mov ebx, 1
mov ecx, [%1]
int 80h
%%done:
popa
%endmacro
%macro syscall 0 ; just to map like x64 syscalls
int 80h
%endmacro
; -- Runtime Ifs --
%macro mod 3
; Usage: mod <var>, <val1> <val2>
; Sets <var> to <val1> % <val2>
%ifndef %1
new dword, %1, 0
%endif
%ifidni %2, eax || %ifidni %2, ebx || %ifidni %2, ecx || %ifidni %2, edx
mov eax, %2
%else
mov eax, [%2]
%endif
xor edx, edx
mov ebx, %3
div ebx
mov [%1], edx
%endmacro
%macro if 3
; Usage: if <var>, mode (>, <, ==), <val>
; Doesn't use %if because that is compile-time
mov eax, [%1]
cmp eax, %3
%ifidni %2, >
jle %1_loop.endif_%1_%3
%elifidni %2, <
jge %1_loop.endif_%1_%3
%else
jne %1_loop.endif_%1_%3
%endif
%endmacro
%macro endif 2
%1_loop.endif_%1_%2:
%endmacro
; -- exit macro --
%macro exit 1
; Usage: exit <status>
%ifidn __TYPE__ %1, "imm"
mov eax, 1
mov ebx, %1
int 80h
%elifnum %1
mov eax, 1
mov ebx, %1
int 80h
%else
mov eax, 1
mov ebx, [%1]
int 80h
%endif
%endmacro
; TODO: Add file i/o to my own std lib
; -- Classes (WIP) --
; -- TODO: Implement class inheritance, `new class <classname>`, static and class methods --
; Workarounds of how to implement classes in assembly
; Create a helper macro to check if class exists before allowing to run, fail at compile time if not
; Use a global variable to store class instances, and a method to create new instances
; class storage
%macro class 1
; Usage: class <classname>
; Example: class MyClass
; Defines a new class with the given name.
%ifidn __CLASS_NAME__, %1
%error "Class '%1' is already defined"
%endif
section .data
global CLASS_%1
CLASS_%1:
%define __CLASS_NAME__ %1
%define __CLASS_STORAGE__ CLASS_%1
%endmacro
%macro method 3
; Usage: method <classname>, <methodname>, <static/clsMethod>
; Example: method MyClass, myMethod, static
; alias of func pretty much
%define __METHOD_NAME__ %2
%define __METHOD_CLASS__ %1
%define __METHOD_TYPE__ %3
%define __METHOD_STORAGE__ CLASS_%1.%2
func CLASS_%1.%2
%endmacro
%macro value 2-*
; Usage: value <classname>.<valuename>, <value>
; declare val as symbol
%ifidn __CLASS_NAME__, %1
%error "Class '%1' is not defined"
%endif
%ifidn __VALSYM__, %1
%if __VALNAME__, %2 ; check to make sure redefinition is not allowed
%error "Value '%2' is already defined in class '%1'"
%endif
%endif
%define __VALSYM__ %1
%define __VALNAME__ %2
%if %0 >= 2
%1:
%ifstr %2
escapeString %2
%else
db %2
%endif
%rotate 2
%rep %0-2
%ifstr %1
escapeString %1
%else
db %1
%endif
%rotate 1
%endrep
%1_len equ $ - %1
%else
%error "Not enough parameters for 'value'"
%endif
%endmacro
%macro run 1
; Usage: run <classname>.<methodname>
; Calls a method of the class.
%ifidn %1, main
call _start
%else
call CLASS_%1
%endif
%endmacro
%endif