Newer
Older
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
typedef unsigned char u8;
typedef int i32;
typedef unsigned int u32;
#if _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define MAP_JIT_VALUE MAP_JIT
void sys_icache_invalidate(void *start, size_t len);
#else
#define MAP_JIT_VALUE 0
#endif
#define Dst ds
#define Dst_DECL dasm_State **ds
#define Dst_REF (*ds)
#define DASM_CHECKS
#include "dasm_proto.h"
#include "dasm_x86.h"
//|.arch x64
//|.actionlist our_dasm_actions
//|.globals DASM_LBL_
our_dasm_link_and_encode(Dst_DECL)
assert(dasm_link(Dst, &size) == DASM_S_OK);
code = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
code = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT_VALUE, -1, 0);
assert(dasm_encode(Dst, code) == DASM_S_OK);
DWORD original;
VirtualProtect(code, size, PAGE_EXECUTE_READ, &original);
mprotect(code, size, PROT_READ | PROT_EXEC);
#endif
#if defined(__APPLE__) && defined(__MACH__)
sys_icache_invalidate(code, size);
}
enum op {
OP_CONSTANT,
OP_ADD,
OP_PRINT,
OP_INPUT,
OP_DISCARD,
OP_GET,
OP_SET,
OP_CMP,
OP_JGT,
OP_HALT,
};
static void *
compile(u8 *program, size_t program_len)
{
dasm_State *dasm_state;
dasm_State **ds = &dasm_state;
dasm_init(Dst, DASM_MAXSECTION);
void *our_dasm_labels[DASM_LBL__MAX];
dasm_setupglobal(Dst, our_dasm_labels, DASM_LBL__MAX);
dasm_setup(Dst, our_dasm_actions);
dasm_growpc(Dst, program_len);
//| push rbx
//| push rbp
//| mov rbp, rsp
//| mov rbx, rdi
u8 *instrptr = program;
u8 *end = program + program_len;
#define OPERAND() ((i32) ( \
((u32)instrptr[1] << 0) | \
((u32)instrptr[2] << 8) | \
((u32)instrptr[3] << 16) | \
((u32)instrptr[4] << 24)))
while (instrptr < end) {
enum op op = (enum op)*instrptr;
int offset = (int) (instrptr - program);
//|=> offset:
//! int3
switch (op) {
case OP_CONSTANT: {
i32 operand = OPERAND();
//| push operand
instrptr += 5; break;
}
case OP_ADD: {
//| pop rcx
//| pop rax
//| add rax, rcx
//| push rax
instrptr += 1; break;
}
case OP_PRINT: {
//| mov64 rdi, ((uintptr_t) "%zd\n")
//| pop rsi
//| mov64 rax, ((uintptr_t) printf)
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
//| call rax
instrptr += 1; break;
}
case OP_INPUT: {
//| mov eax, dword [rbx]
//| push rax
//| add rbx, 4
instrptr += 1; break;
}
case OP_DISCARD: {
//| pop rax
instrptr += 1; break;
}
case OP_GET: {
//| mov rax, [rsp + 8 * OPERAND()]
//| push rax
instrptr += 5; break;
}
case OP_SET: {
//| pop rax
//| mov [rsp + 8 * OPERAND()], rax
instrptr += 5; break;
}
case OP_CMP: {
//| pop rcx
//| pop rax
//| cmp rax, rcx
//| jg >1
//| je >2
//| push -1
//| jmp >3
//|1:
//| push 1
//| jmp >3
//|2:
//| push 0
//|3:
instrptr += 1; break;
}
int offset = (int) (instrptr - program + OPERAND());
//| pop rax
//| test rax, rax
//| jg => offset
instrptr += 5; break;
//| mov rsp, rbp
//| pop rbp
//| pop rbx
//| ret
instrptr += 1; break;
}
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
dasm_free(Dst);
return code;
}
int
main(int argc, char **argv)
{
u8 program[] = {
OP_INPUT, OP_INPUT,
OP_CONSTANT, 0, 0, 0, 0,
OP_GET, 0, 0, 0, 0,
OP_GET, 3, 0, 0, 0,
OP_ADD,
OP_SET, 0, 0, 0, 0,
OP_GET, 1, 0, 0, 0,
OP_CONSTANT, 0xff, 0xff, 0xff, 0xff, // -1 32-bit little-endian (two's complement)
OP_ADD,
OP_SET, 1, 0, 0, 0,
OP_GET, 1, 0, 0, 0,
OP_CONSTANT, 0, 0, 0, 0,
OP_CMP,
OP_JGT, 0xd5, 0xff, 0xff, 0xff, // -43 in 32-bit little-endian (two's complement)
OP_GET, 0, 0, 0, 0,
OP_PRINT,
OP_HALT,
};
if (argc != 3) {
fprintf(stderr, "Expected exactly 2 arguments\n");
return 1;
}
i32 input[] = { atoi(argv[1]), atoi(argv[2]) };
void (*fun)(i32 *input) = compile(program, sizeof(program));