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 rbp
//| mov rbp, rsp
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: {
int32_t operand = OPERAND();
//| mov dword [rdx], operand
//| add rdx, 4
//| mov ecx, dword [rdx - 4]
//| add [rdx - 8], ecx
//| sub rdx, 4
//| mov64 rax, ((uintptr_t) printf)
instrptr += 1; break;
}
case OP_INPUT: {
//| mov eax, dword [rbx]
//| add rbx, 4
instrptr += 1; break;
}
case OP_DISCARD: {
//| mov eax, dword [rdx - 4 - 4 * OPERAND()]
//| mov dword [rdx], eax
//| add rdx, 4
//| mov eax, dword [rdx - 4]
//| sub rdx, 4
//| mov dword [rdx - 4 - 4 * OPERAND()], eax
//| test rax, rax
//| jg => offset
instrptr += 5; break;
//| mov rsp, rbp
//| pop rbp
//| ret
instrptr += 1; break;
}
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
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));