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
|
#include "../executor.h"
#include "../../include/program.h"
#include "../../include/std/alloc.h"
#include <assert.h>
typedef struct {
usize *stack;
usize stack_size;
usize stack_index;
isize reg[AMAL_PROGRAM_NUM_REGISTERS];
} amal_executor_impl;
#define IMPL \
amal_executor_impl *impl; \
impl = (amal_executor_impl*)self;
#define FOUR_MEGABYTES 1024*1024*4
static int executor_ensure_stack_capacity(amal_executor_impl *self, usize bytes_to_add) {
const isize overflow = self->stack_size - self->stack_index * sizeof(isize) + bytes_to_add;
if(overflow > 0) {
void *new_data;
const usize new_stack_size = self->stack_size * 1.5;
if(new_stack_size > FOUR_MEGABYTES)
return AMAL_PROGRAM_INSTRUCTION_STACK_OVERFLOW;
return_if_error(am_realloc(self->stack, new_stack_size, &new_data));
self->stack = new_data;
self->stack_size = new_stack_size;
}
return 0;
}
int amal_executor_init(amal_executor **self) {
amal_executor_impl **impl;
impl = (amal_executor_impl**)self;
*impl = NULL;
return_if_error(am_malloc(sizeof(amal_executor_impl), (void**)impl));
(*impl)->stack_size = 4096;
return_if_error(am_malloc((*impl)->stack_size, (void**)&(*impl)->stack));
(*impl)->stack_index = 0;
return 0;
}
void amal_executor_deinit(amal_executor *self) {
IMPL
am_free(impl->stack);
am_free(impl);
}
int amal_executor_run(amal_executor *self) {
(void)self;
assert(bool_false && "TODO: Implement!");
return 0;
}
int amal_exec_nop(amal_executor *self) {
(void)self;
return 0;
}
int amal_exec_setz(amal_executor *self, u8 dst_reg) {
IMPL
impl->reg[dst_reg] = 0;
return 0;
}
int amal_exec_mov(amal_executor *self, u8 dst_reg, u8 src_reg) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg];
return 0;
}
int amal_exec_movi(amal_executor *self, u8 dst_reg, i64 imm) {
IMPL
impl->reg[dst_reg] = imm;
return 0;
}
int amal_exec_movd(amal_executor *self, u8 dst_reg, BufferView data) {
IMPL
impl->reg[dst_reg] = (uintptr_t)data.data;
return 0;
}
int amal_exec_add(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg1] + impl->reg[src_reg2];
return 0;
}
int amal_exec_sub(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg1] - impl->reg[src_reg2];
return 0;
}
int amal_exec_imul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg1] * impl->reg[src_reg2];
return 0;
}
int amal_exec_mul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg1] * impl->reg[src_reg2];
return 0;
}
int amal_exec_idiv(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg1] / impl->reg[src_reg2];
return 0;
}
int amal_exec_div(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = impl->reg[src_reg1] / impl->reg[src_reg2];
return 0;
}
int amal_exec_push(amal_executor *self, u8 reg) {
IMPL
return_if_error(executor_ensure_stack_capacity(impl, sizeof(isize)));
impl->stack[impl->stack_index++] = impl->reg[reg];
return 0;
}
int amal_exec_pushi(amal_executor *self, i64 imm) {
IMPL
return_if_error(executor_ensure_stack_capacity(impl, sizeof(isize)));
impl->stack[impl->stack_index++] = imm;
return 0;
}
int amal_exec_pushd(amal_executor *self, BufferView data) {
IMPL
return_if_error(executor_ensure_stack_capacity(impl, sizeof(isize)));
impl->stack[impl->stack_index++] = (uintptr_t)data.data;
return 0;
}
/*int amal_exec_call(u8 dst_reg, BufferView data);
int amal_exec_callr(u8 dst_reg, BufferView data);*/
int amal_exec_cmp(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
IMPL
impl->reg[dst_reg] = (impl->reg[src_reg1] == impl->reg[src_reg2]);
return 0;
}
int amal_exec_jz(amal_executor *self, u8 dst_reg, i16 offset) {
(void)self;
(void)dst_reg;
(void)offset;
/* TODO: Implement! */
assert(bool_false && "TODO: Implement!");
return 0;
}
int amal_exec_jmp(amal_executor *self, i16 offset) {
(void)self;
(void)offset;
/* TODO: Implement! */
assert(bool_false && "TODO: Implement!");
return 0;
}
int amal_exec_ret(amal_executor *self) {
(void)self;
/* TODO: Implement! */
assert(bool_false && "TODO: Implement RET. RET needs to restore the stack before returning");
return 0;
}
int amal_exec_func_start(amal_executor *self, u16 num_regs) {
/*
TODO: Validate stack size, or maybe remove all validation? do we really need validation?
If we need security, we could fork the process instead.
*/
/*
Some registers need to be preserved before entering a function scope and these registers are different on different platforms.
32-bit: EBX, ESI, EDI, EBP
64-bit Windows: RBX, RSI, RDI, RBP, R12-R15, XMM6-XMM15
64-bit Linux,BSD,Mac: RBX, RBP, R12-R15
*/
/* TODO: Preserve registers and stack frame */
/*return executor_ensure_stack_capacity(impl, num_regs * sizeof(isize));*/
(void)self;
(void)num_regs;
return 0;
}
int amal_exec_func_end(amal_executor *self) {
(void)self;
/* TODO: Restore registers and stack frame and ret */
return 0;
}
|