-
Notifications
You must be signed in to change notification settings - Fork 0
/
code_gen_map.txt
550 lines (456 loc) · 15.5 KB
/
code_gen_map.txt
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
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
/**
* This is a blueprint pseudo code representation of how the AST will
* be traversed for code generation. After the blueprint is ready, the
* pseudo code can be translated into C code.
*/
This might be helpful: https://www.cs.uaf.edu/2005/fall/cs301/support/x86/nasm.html
NASM Documentation: https://www.nasm.us/xdoc/2.14.02/nasmdoc.pdf
To compile nasm programs:
nasm -f elf <file_name>.asm
To link files using gcc (on 64 bits systems) (Requires global main):
gcc -m32 <file_name>.o -o <file_name>
To link files using gcc (on 32 bits systems) (Requires global main):
gcc <file_name>.o -o <file_name>
To link files using ld (Requires global _start):
ld -m elf_i386 <file_name>.o -o <out_file_name>
To run the compiled program:
./<out_file_name>
/* ---- Sample NASM program ---- */
section .data
msg db 'Hello world!',0Ah;
section .text
global main ; _start when linking with ld
main:
mov edx, 13 ;number of bytes to write
mov ecx, msg ;move memory address of our message string
mov ebx, 1 ;write to stdout
mov eax, 4 ;marshal system write system call opcode into eax
int 80h ;generate interrupt
mov ebx, 0 ;return 0 status on exit - 'No errors'
mov eax, 1 ;invoke SYS_EXIT system call (kernel opcode 1)
int 80h ;generate interrupt
/* --------------------------- */
/* ---- A standard way to setup stack frames [makes debugging easy] ---- */
https://stackoverflow.com/questions/17239781/x86-assembly-why-do-i-need-stack-frames
/* Saves the pointer to the base of current stack frame, and moves stack pointer to
ebx. Thus we are free to use stack inside the called function */
| #(ebp) (old) | | | | $(esp) (old), #ebp (new)| | | | | | | $(esp)(new) | |
/*setting the stack frame*/
push ebp
mov ebp,esp
add esp, actRecSize
...
code goes here
...
/*removing the stack frame*/
mov esp, ebp
pop ebp
/* ---------------------------------------------------------------------- */
traverseAST(): {
switch on type pf AST node: {
AST_NODE_PROGRAM: {
/* init text and data section here */
----
section .data
;define all the global variables here
msg db "hello"
section .text
global main ;NOTE: In case you are linking with ld, use _start. Use main when linking with gcc
----
}
AST_NODE_MODULEDECLARATION: {
/* Helps only in construction of symbol table */
}
AST_NODE_MODULELIST: {
/* Helps in AST traversal */
}
AST_NODE_MODULE: {
/* start module definition. Get SymbolTableFunc for this module
It is assumed that the caller has pushed the relevant arguments into the stack, and has pushed
the address of the arguments at the end. Also, ebp points to the start of the stack frame */
----
%module_name:
----
/* Everything can be accessed in the stack frame */
----
;Do stuff
----
}
AST_NODE_INPUTLIST: {
/* Helps only in construction of symbol table */
}
AST_NODE_OUTPUTLIST: {
/* Helps only in construction of symbol table */
}
AST_NODE_ARRAY: {
/* TODO */
}
AST_NODE_RANGEARRAYS:
AST_NODE_STATEMENT: {
if child is NULL
if these block of statements belong to a moduleDef:
---
ret
---
/* TODO: Handle other cases */
}
AST_NODE_IO: {
/* Fetch the variable from the symbol table on which the I/O is called */
if get_val:
/* Get value is on ID. That means we cant get value into an array type.
Get the variable from symbol table. It must have an offset. */
----
mov edx, ID.width ; number of bytes to read
mov ecx, ebp + offset ; reserved space to store the input
mov ebx, 0 ; write to stdin
mov eax, 3 ; invoke SYS_READ (kernel opcode 3)
int 80h ; interrupt, switch context to kernel
----
else if put_val:
/* Put value is on var
var -> var_id_num
var_id_num -> ID, ID[index], NUM, RNUM */
if ID:
/* Get the symbol table entry for ID and its offset */
----
mov edx, ID.width ;number of bytes to write
mov ecx, ebp + offset ;move memory address of the value
----
else if ID[index]:
----
mov edx, ID.(width of each element)
mov ecx, ebp + offset + index*(width of each element)
----
else:
/* not sure what to do here */
----
mov edx, NUM.width | RNUM.width
mov ecx, NUM | RNUM ; Not sure how to output constant, we dont need memory location here
----
----
mov ebx, 1 ;write to stdout
mov eax, 4 ;marshal system write system call opcode into eax
int 80h ;generate interrupt
----
}
AST_NODE_SIMPLESTMT: {
/* Just traverse */
}
AST_NODE_ASSIGN: {
/* Traverse first. This will assume that rhs will have values stored in stack */
ch = curr->child
ch = ch->next;
traverseAST(ch, fname);
----
mov ax, <temp_rhs>.offset ; Requires more discussion
mov [ebp + <lhs>.offset], ax
----
}
AST_NODE_MODULEREUSE: {
/* Setting the stack frame. */
/* Get symbolTableFunc for the called module. */
;eax, ecx, ebx, edx, esi , edi, esp , ebp
----
;Save the current stack frame pointer
pusha ;ebp
;Move the current pointer to stack as the base of the called function.
;This makes sure that we are free to stack pointer now
mov ebp,esp
----
/* Iterate through output_plist, and reserve that much space at
the base of the stack frame */
actRecSize = sum of width of output_plist + input_plist + local variables + temporary variables
----
sub esp, actRecSize
----
[ebp + offset_a]
/* Iterate in through args list, and assign them values at their offsets in the frame */
for each <arg> in modulereuse.args and corresponsing <input_param> in input_plist:
mov ax, <arg>.value
mov [ebp + <input_param>.offset], ax
----
/* call the function */
----
call %name_of_module
----
/* removing the stack frame */
----
mov esp, ebp
popa ; ebp
----
[a,b] = modulereuse func1 with params [4,5]
| ebp (old)|.... |esp(old)| ..pusha... | ebp(new) | + offset
/* Store the output.
We can do this by iterating through the output_plist */
for each <output_param> in the output_plist:
----
mov ax, [esp + (memory_organisation)*8 + <output_param>.offset] ; take care of byte org/word org
mov [ebp + <left_arg>.offset], ax
----
<left_Arg> = <left_arg>.next;
}
AST_NODE_IDLIST:
AST_NODE_EXPR:
AST_NODE_AOBEXPR: {
x = a + c - d / e;
a + AOB (t2)
c - AOB (t1) <--
d / num
when leaf:
mov EAX, [d]
mov EBX, NUM
DIV EAX, EBX
MOV [t1], EAX
/// repeat
when non-leaf:
get t1
mov ax, [t1]
mov bx, [c]
sub ax, bx
mov [t2], ax
}
AST_NODE_DECLARESTMT:
AST_NODE_CONDSTMT:
AST_NODE_CASESTMT:
AST_NODE_UNARY:
AST_NODE_LVALARRSTMT:
AST_NODE_ITERSTMT:
AST_NODE_VARIDNUM:
AST_NODE_LEAF: {
switch on leaf type: {
AST_LEAF_INT:
AST_LEAF_RNUM:
AST_LEAF_BOOL:
AST_LEAF_ID: {
switch on parent type {
AST_NODE_MODULEDECLARATION:
AST_NODE_MODULE:
AST_NODE_INPUTLIST:
AST_NODE_OUTPUTLIST:
AST_NODE_IO:
AST_NODE_VARIDNUM:
AST_NODE_LVALARRSTMT:
AST_NODE_ASSIGN:
AST_NODE_MODULEREUSE: {
}
AST_NODE_IDLIST: {
/* Only for AST iteration */
}
AST_NODE_CONDSTMT: {
}
AST_NODE_ITERSTMT:
}
}
AST_LEAF_NUM:
AST_LEAF_IDXNUM:
AST_LEAF_IDXID:
AST_LEAF_PLUS:
AST_LEAF_MINUS:
AST_LEAF_MUL:
AST_LEAF_DIV:
AST_LEAF_OR:
AST_LEAF_AND:
AST_LEAF_LT:
AST_LEAF_LE:
AST_LEAF_GT:
AST_LEAF_GE:
AST_LEAF_EQ:
AST_LEAF_NE:
AST_LEAF_TRUE:
AST_LEAF_FALSE:
AST_LEAF_VALNUM:
AST_LEAF_VALTRUE:
AST_LEAF_VALFALSE:
AST_LEAF_VARIDNUM_NUM:
AST_LEAF_VARIDNUM_ID:
AST_LEAF_VARIDNUM_RNUM:
AST_LEAF_BOOLTRUE:
AST_LEAF_BOOLFALSE:
AST_LEAF_UOPPLUS:
AST_LEAF_UOPMINUS:
default:
}
}
}
}
COND1:
COND2:
FOR1:
FOR2:
FOR3:
WHILE1:
WHILE2:
switch(var) {
case 1: //
switch(var1) {
case 4:
case 5:
}
case 3: //
default: //
}
cmp bla, case_val
jne curr -> nextJump
....
goto switch -> nextJump
jne bla2 curr -> nextJump
How to use printf in NASM:
http://nasmcodeasy.blogspot.com/2014/04/using-c-printf-in-nasm.html
----------------------------------------------------------
FPU
----------
; finit
; fld dword []
; fld qword []
; fld tword []
; fadd/fmul/fdiv/fcom
; fstp dword []
; fstsw ax ; FPU status register / analogous to flag
section .data
msg db 'Hello world!',0Ah;
omega dd 2.3
omega2 dd 3.5
print_format db "Result: %f",0xA,0
section .text
global main: ; _start when linking with ld
main:
;push dword rax
;push dword rbx
finit
fld dword [omega]
fld dword [omega2]
fadd
mov rsp, 4
fistp dword [omega2]
mov rdx, 4 ;number of bytes to write
mov rax, rsp
sub rax, 4
mov rcx, omega2 ;move memory address of our message string
mov rbx, 1 ;write to stdout
mov rax, 4 ;marshal system write system call opcode into eax
int 80h ;generate interrupt
mov rbx, 0 ;return 0 status on exit - 'No errors'
mov rax, 1 ;invoke SYS_EXIT system call (kernel opcode 1)
int 80h ;generate interrupt
st0 = [mem1] + [mem] + [mem2]
st1 = [mem1] + [mem]
st2 = [mem]
st3
st4
...
st7
finit
fld [mem]
fld [mem1]
fadd
fld [mem2]
fadd
fistp dword [ebp + offset]
----------------------------------------------------------------------------------
| METHOD TO ADD TWO FLOATING POINT NUMBERS IN x86-64 NASM AND print using printf |
----------------------------------------------------------------------------------
global main
extern printf, scanf
section .data
scan_format: db "%f",0
print_format: db "Result: %f",0xA,0
result_num: dq 9.35
result_num2: dq 4.87
section .text
main:
finit
fld qword [result_num]
fld qword [result_num2]
fadd
;sub rsp,8 ;reserve stack for a double in stack
;push rbp
fstp qword [result_num]
push rbp
mov rdi, print_format ; format for printf
movq xmm0, qword [result_num]
mov rax, 1
call printf
pop rbp
mov rax, 0
ret
----------------------------------------------------------------------------------
| METHOD TO scan TWO FLOATING POINT NUMBERS IN x86-64 NASM using scanf |
----------------------------------------------------------------------------------
section .data
fmt: db "%lf %lf", 0
p_fmt: db "%lf %lf", 0xA, 0
section .bss
var1: resb 8
var2: resb 8
section .text
global main
extern printf, scanf
main:
push rbp
mov rdi, fmt
mov rsi, var1
mov rdx, var2
call scanf
pop rbp
push rbp
mov rdi, p_fmt
movq xmm0, qword [var1]
movq xmm1, qword [var2]
mov rax, 2
call printf
pop rbp
ret
--------------------------------------------------------------
-----------------------------------------------------------------------------------
| METHOD TO immediately load a float value and add floating point numbers without |
| using FPU unit |
-----------------------------------------------------------------------------------
section .data
print_format_xmm: db "Result from XMM: %f",0xA,0
print_format_mem: db "Result from Memory: %f",0xA,0
val: dw 2
section .bss
buffer: resb 4
section .text
global main
extern scanf, printf
main:
mov dword [buffer], __float32__(9.35)
; This uses addsd instruction in x86 to add an integer to immediate float
; This can be done without FPU stack
cvtss2sd xmm0, __float32__(9.35)
cvtsi2sd xmm1, [val]
cvtss2sd xmm0, [buffer]
addsd xmm0, xmm1
movss dword [buffer], xmm0 ; There is some problem here
movq rax, xmm0
push rbp
mov rdi, print_format_xmm ; format for printf
mov rax, 1
call printf
pop rbp
mov rax, 0
;--------------------------------------------
push rbp
mov rdi, print_format_mem ; format for printf
movss xmm0, dword [buffer]
mov rax, 1
call printf
pop rbp
mov rax, 0
ret
;------------------------------------------------------------------
declareStmt : DECLARE idList COLON dataType SEMICOL
case AST_NODE_DECLARESTMT:
ASTNode* ch = curr-> child;
push rbp
F | ^
E | |
D | |
C | |
B |[rbp]
A | |
9 | |
8 | \/
7 | <--- rsp, rbp
mpv rcx, qword [rbp + 1]; read from 7 to E!