-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathamd64_asm.c
136 lines (115 loc) · 3.83 KB
/
amd64_asm.c
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
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "back.h"
#include "bfir.h"
#include "label.h"
#include "out.h"
#include "amd64_asm.h"
static const char *amd64_cellp = "rbx";
static void amd64_asm_instr(Out_Channel *out, Bfir_Instr *instr, Label_Stack *stack, Label_Id *fresh, Amd64_Asm_Flag flags) {
Label_Id label;
switch (instr->kind) {
case BFIR_ADD:
out_print(out, "\tadd BYTE [%s], %ld\n", amd64_cellp, instr->arg);
break;
case BFIR_ADDP:
out_print(out, "\tadd %s, %ld\n", amd64_cellp, instr->arg);
break;
case BFIR_READ:
if (flags & AMD64_ASM_READ_SYSCALL) {
out_print(out, "\tmov rax, 0\n");
out_print(out, "\tmov rdi, 0\n");
out_print(out, "\tmov rsi, rbx\n");
out_print(out, "\tmov rdx, %ld\n", instr->arg);
out_print(out, "\tsyscall\n");
} else {
assert(instr->arg == 1);
out_print(out, "\tcall [rel getchar wrt ..got]\n");
out_print(out, "\tmov BYTE [%s], al\n", amd64_cellp);
}
break;
case BFIR_WRITE:
if (flags & AMD64_ASM_WRITE_SYSCALL) {
out_print(out, "\tmov rax, 1\n");
out_print(out, "\tmov rdi, 1\n");
out_print(out, "\tmov rsi, rbx\n");
out_print(out, "\tmov rdx, %ld\n", instr->arg);
out_print(out, "\tsyscall\n");
} else {
assert(instr->arg == 1);
out_print(out, "\tmovzx edi, BYTE [%s]\n", amd64_cellp);
out_print(out, "\tcall [rel putchar wrt ..got]\n");
}
break;
case BFIR_JMPF:
label = ++(*fresh);
out_print(out, ".L%uf:\n", label);
out_print(out, "\tmov al, BYTE [%s]\n", amd64_cellp);
out_print(out, "\ttest al, al\n");
out_print(out, "\tje .L%ub\n", label);
label_stack_push(stack, label);
break;
case BFIR_JMPB:
assert(label_stack_pop(stack, &label) && "Unpaired jumps");
out_print(out, "\tjmp .L%uf\n", label);
out_print(out, ".L%ub:\n", label);
break;
default:
assert(false && "Unreachable");
}
}
static void amd64_asm_entry(Out_Channel *out, Bfir_Entry *entry, Label_Stack *stack, size_t celln, Amd64_Asm_Flag flags) {
out_print(out, "\tbits 64\n");
if (!(flags & AMD64_ASM_READ_SYSCALL)) out_print(out, "\textern getchar\n\n");
if (!(flags & AMD64_ASM_WRITE_SYSCALL)) out_print(out, "\textern putchar\n");
out_print(out, "\tsection .bss\n");
out_print(out, "\talign 32\n");
out_print(out, "__cells:\n");
out_print(out, "\tresb %zu\n\n", celln);
out_print(out, "\tsection .text\n");
out_print(out, "\tglobal %s\n", entry->name);
out_print(out, "\talign 16\n");
out_print(out, "%s:\n", entry->name);
out_print(out, "\tpush rbp\n");
out_print(out, "\tmov rbp, rsp\n");
out_print(out, "\tpush rbx\n");
out_print(out, "\tmov %s, __cells\n", amd64_cellp);
if (entry->head != 0) {
Label_Id fresh = 0;
Bfir_Instr *instr = bfir_entry_get(entry, entry->head);
while (true) {
amd64_asm_instr(out, instr, stack, &fresh, flags);
if (instr->next == 0) break;
instr = bfir_entry_get(entry, instr->next);
}
}
assert(stack->len == 0 && "Unpaired jumps");
out_print(out, "\tmov rax, 0\n");
out_print(out, "\tpop rbx\n");
out_print(out, "\tpop rbp\n");
out_print(out, "\tret\n");
}
void amd64_asm_aux_init(Amd64_Asm_Aux *aux, Label_Stack *stack, size_t celln, Amd64_Asm_Flag flags) {
assert(aux != NULL);
assert(stack != NULL);
assert(celln != 0);
aux->aux.sign = amd64_asm_back.sign;
aux->stack = stack;
aux->celln = celln;
aux->flags = flags;
}
Error amd64_asm_emit(Out_Channel *out, Bfir_Entry *entry, Back_Aux *aux) {
assert(out != NULL && entry != NULL && aux != NULL);
assert(aux->sign.quad == amd64_asm_back.sign.quad);
amd64_asm_entry(out, entry, ((Amd64_Asm_Aux *)aux)->stack, ((Amd64_Asm_Aux *)aux)->celln, ((Amd64_Asm_Aux *)aux)->flags);
// TODO: Implement error handling
Error error = { NULL };
return error;
}
const Back_Info amd64_asm_back = {
.sign.quad = 0x866400008664aaaa,
.emit_f = amd64_asm_emit,
};