-
Notifications
You must be signed in to change notification settings - Fork 16
/
jit.c
166 lines (158 loc) · 5.32 KB
/
jit.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
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
#include <assert.h> // assert
#include <stdio.h> // putchar, getchar
#include <stdlib.h> // free
#include <string.h> // memcpy
#include <sys/mman.h> // mmap
#include "vector.h"
#include "stack.h"
#include "file_io.h"
#include "debug.h"
// return 0 is success
#define GUARD(expr) assert(!(expr))
typedef void* fn_memset (void*, int, size_t);
typedef int fn_putchar (int);
typedef int fn_getchar ();
void jit (const char* const file_contents) {
struct vector instruction_stream;
struct stack relocation_table = { .size = 0, .items = { 0 } };
int relocation_site = 0;
int relative_offset = 0;
GUARD(vector_create(&instruction_stream, 100));
char prologue [] = {
0x55, // push rbp
0x48, 0x89, 0xE5, // mov rsp, rbp
// backup callee saved registers
0x41, 0x54, // pushq %r12
0x41, 0x55, // pushq %r13
0x41, 0x56, // pushq %r14
// %rdi = memset
// %rsi = putchar
// %rdx = getgetchar
// backup args to callee saved registers
0x49, 0x89, 0xFC, // movq %rdi, %r12
0x49, 0x89, 0xF5, // movq %rsi, %r13
0x49, 0x89, 0xD6, // movq %rdx, %r14
// %r12 = memset
// %r13 = putchar
// %r14 = getchar
// allocate 30,008 B on stack
0x48, 0x81, 0xEC, 0x38, 0x75, 0x00, 0x00, // subq $30000, %rsp
// address of beginning of tape
0x48, 0x8D, 0x3C, 0x24, // leaq (%rsp), %rdi
// fill with 0's
0xBE, 0x00, 0x00, 0x00, 0x00, // movl $0, %esi
// length 30,000 B
0x48, 0xC7, 0xC2, 0x30, 0x75, 0x00, 0x00, // movq $30000, %rdx
// memset
0x41, 0xFF, 0xD4, // callq *%r12
0x49, 0x89, 0xE4 // movq %rsp, %r12
// %r12 = &tape[0];
};
GUARD(vector_push(&instruction_stream, prologue, sizeof(prologue)));
for (unsigned long i = 0; file_contents[i] != '\0'; ++i) {
switch (file_contents[i]) {
case '>':
// see: http://stackoverflow.com/a/8550253/1027966
{
char opcodes [] = {
0x49, 0xFF, 0xC4 // inc %r12
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
break;
case '<':
{
char opcodes [] = {
0x49, 0xFF, 0xCC // dec %r12
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
break;
case '+':
{
char opcodes [] = {
0x41, 0xFE, 0x04, 0x24 // incb (%r12)
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
break;
case '-':
{
char opcodes [] = {
0x41, 0xFE, 0x0C, 0x24 // decv (%r12)
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
break;
case '.':
{
char opcodes [] = {
0x41, 0x0F, 0xB6, 0x3C, 0x24, // movzbl (%r12), %edi
0x41, 0xFF, 0xD5 // callq *%r13
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
break;
case ',':
{
char opcodes [] = {
0x41, 0xFF, 0xD6, // callq *%r14
0x41, 0x88, 0x04, 0x24 // movb %al, (%r12)
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
break;
case '[':
{
char opcodes [] = {
0x41, 0x80, 0x3C, 0x24, 0x00, // cmpb $0, (%r12)
// Needs to be patched up
0x0F, 0x84, 0x00, 0x00, 0x00, 0x00 // je <32b relative offset, 2's compliment, LE>
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
GUARD(stack_push(&relocation_table, instruction_stream.size)); // create a label after
break;
case ']':
{
char opcodes [] = {
0x41, 0x80, 0x3C, 0x24, 0x00, // cmpb $0, (%r12)
// Needs to be patched up
0x0F, 0x85, 0x00, 0x00, 0x00, 0x00 // jne <32b relative offset, 2's compliment, LE>
};
GUARD(vector_push(&instruction_stream, opcodes, sizeof(opcodes)));
}
// patches self and matching open bracket
GUARD(stack_pop(&relocation_table, &relocation_site));
relative_offset = instruction_stream.size - relocation_site;
vector_write32LE(&instruction_stream, instruction_stream.size - 4, -relative_offset);
vector_write32LE(&instruction_stream, relocation_site - 4, relative_offset);
break;
}
}
char epilogue [] = {
0x48, 0x81, 0xC4, 0x38, 0x75, 0x00, 0x00, // addq $30008, %rsp
// restore callee saved registers
0x41, 0x5E, // popq %r14
0x41, 0x5D, // popq %r13
0x41, 0x5C, // popq %r12
0x5d, // pop rbp
0xC3 // ret
};
GUARD(vector_push(&instruction_stream, epilogue, sizeof(epilogue)));
/*print_instruction_stream(&instruction_stream);*/
void* mem = mmap(NULL, instruction_stream.size, PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE, -1, 0);
memcpy(mem, instruction_stream.data, instruction_stream.size);
void (*jitted_func) (fn_memset, fn_putchar, fn_getchar) = mem;
jitted_func(memset, putchar, getchar);
munmap(mem, instruction_stream.size);
vector_destroy(&instruction_stream);
}
int main (int argc, char* argv []) {
if (argc != 2) err("Usage: jit inputfile");
char* file_contents = read_file(argv[1]);
if (file_contents == NULL) err("Couldn't open file");
jit(file_contents);
free(file_contents);
}