Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
compiler_x86.c
1/* Copyright (c) 2020 tevador <tevador@gmail.com> */
2/* See LICENSE for licensing information */
3
4#include <string.h>
5
6#include "compiler.h"
7#include "program.h"
8#include "virtual_memory.h"
9#include "unreachable.h"
10
11#if defined(_WIN32) || defined(__CYGWIN__)
12#define WINABI
13#endif
14
15#define EMIT(p,x) do { \
16 memcpy(p, x, sizeof(x)); \
17 p += sizeof(x); \
18 } while (0)
19#define EMIT_BYTE(p,x) *((p)++) = x
20#define EMIT_U16(p,x) *((uint16_t*)(p)) = x; p += sizeof(uint16_t)
21#define EMIT_U32(p,x) *((uint32_t*)(p)) = x; p += sizeof(uint32_t)
22#define EMIT_U64(p,x) *((uint64_t*)(p)) = x; p += sizeof(uint64_t)
23
24#define GEN_SIB(scale, index, base) ((scale << 6) | (index << 3) | base)
25
26#ifdef HASHX_COMPILER_X86
27
28/* Largest compiled instruction (BRANCH) */
29#define COMP_MAX_INSTR_SIZE 10
30
31static const uint8_t x86_prologue[] = {
32#ifndef WINABI
33 0x48, 0x89, 0xF9, /* mov rcx, rdi */
34 0x48, 0x83, 0xEC, 0x20, /* sub rsp, 32 */
35 0x4C, 0x89, 0x24, 0x24, /* mov qword ptr [rsp+0], r12 */
36 0x4C, 0x89, 0x6C, 0x24, 0x08, /* mov qword ptr [rsp+8], r13 */
37 0x4C, 0x89, 0x74, 0x24, 0x10, /* mov qword ptr [rsp+16], r14 */
38 0x4C, 0x89, 0x7C, 0x24, 0x18, /* mov qword ptr [rsp+24], r15 */
39#else
40 0x4C, 0x89, 0x64, 0x24, 0x08, /* mov qword ptr [rsp+8], r12 */
41 0x4C, 0x89, 0x6C, 0x24, 0x10, /* mov qword ptr [rsp+16], r13 */
42 0x4C, 0x89, 0x74, 0x24, 0x18, /* mov qword ptr [rsp+24], r14 */
43 0x4C, 0x89, 0x7C, 0x24, 0x20, /* mov qword ptr [rsp+32], r15 */
44 0x48, 0x83, 0xEC, 0x10, /* sub rsp, 16 */
45 0x48, 0x89, 0x34, 0x24, /* mov qword ptr [rsp+0], rsi */
46 0x48, 0x89, 0x7C, 0x24, 0x08, /* mov qword ptr [rsp+8], rdi */
47#endif
48 0x31, 0xF6, /* xor esi, esi */
49 0x8D, 0x7E, 0xFF, /* lea edi, [rsi-1] */
50 0x4C, 0x8B, 0x01, /* mov r8, qword ptr [rcx+0] */
51 0x4C, 0x8B, 0x49, 0x08, /* mov r9, qword ptr [rcx+8] */
52 0x4C, 0x8B, 0x51, 0x10, /* mov r10, qword ptr [rcx+16] */
53 0x4C, 0x8B, 0x59, 0x18, /* mov r11, qword ptr [rcx+24] */
54 0x4C, 0x8B, 0x61, 0x20, /* mov r12, qword ptr [rcx+32] */
55 0x4C, 0x8B, 0x69, 0x28, /* mov r13, qword ptr [rcx+40] */
56 0x4C, 0x8B, 0x71, 0x30, /* mov r14, qword ptr [rcx+48] */
57 0x4C, 0x8B, 0x79, 0x38 /* mov r15, qword ptr [rcx+56] */
58};
59
60static const uint8_t x86_epilogue[] = {
61 0x4C, 0x89, 0x01, /* mov qword ptr [rcx+0], r8 */
62 0x4C, 0x89, 0x49, 0x08, /* mov qword ptr [rcx+8], r9 */
63 0x4C, 0x89, 0x51, 0x10, /* mov qword ptr [rcx+16], r10 */
64 0x4C, 0x89, 0x59, 0x18, /* mov qword ptr [rcx+24], r11 */
65 0x4C, 0x89, 0x61, 0x20, /* mov qword ptr [rcx+32], r12 */
66 0x4C, 0x89, 0x69, 0x28, /* mov qword ptr [rcx+40], r13 */
67 0x4C, 0x89, 0x71, 0x30, /* mov qword ptr [rcx+48], r14 */
68 0x4C, 0x89, 0x79, 0x38, /* mov qword ptr [rcx+56], r15 */
69#ifndef WINABI
70 0x4C, 0x8B, 0x24, 0x24, /* mov r12, qword ptr [rsp+0] */
71 0x4C, 0x8B, 0x6C, 0x24, 0x08, /* mov r13, qword ptr [rsp+8] */
72 0x4C, 0x8B, 0x74, 0x24, 0x10, /* mov r14, qword ptr [rsp+16] */
73 0x4C, 0x8B, 0x7C, 0x24, 0x18, /* mov r15, qword ptr [rsp+24] */
74 0x48, 0x83, 0xC4, 0x20, /* add rsp, 32 */
75#else
76 0x48, 0x8B, 0x34, 0x24, /* mov rsi, qword ptr [rsp+0] */
77 0x48, 0x8B, 0x7C, 0x24, 0x08, /* mov rdi, qword ptr [rsp+8] */
78 0x48, 0x83, 0xC4, 0x10, /* add rsp, 16 */
79 0x4C, 0x8B, 0x64, 0x24, 0x08, /* mov r12, qword ptr [rsp+8] */
80 0x4C, 0x8B, 0x6C, 0x24, 0x10, /* mov r13, qword ptr [rsp+16] */
81 0x4C, 0x8B, 0x74, 0x24, 0x18, /* mov r14, qword ptr [rsp+24] */
82 0x4C, 0x8B, 0x7C, 0x24, 0x20, /* mov r15, qword ptr [rsp+32] */
83#endif
84 0xC3 /* ret */
85};
86
87bool hashx_compile_x86(const hashx_program* program, uint8_t* code) {
88 if (!hashx_vm_rw(code, COMP_CODE_SIZE))
89 return false;
90 uint8_t* pos = code;
91 uint8_t* target = NULL;
92 EMIT(pos, x86_prologue);
93 for (size_t i = 0; i < program->code_size; ++i) {
94 if (pos + COMP_MAX_INSTR_SIZE > code + COMP_CODE_SIZE)
95 return false;
96 const instruction* instr = &program->code[i];
97 switch (instr->opcode)
98 {
99 case INSTR_UMULH_R:
100 EMIT_U64(pos, 0x8b4ce0f749c08b49 |
101 (((uint64_t)instr->src) << 40) |
102 (((uint64_t)instr->dst) << 16));
103 EMIT_BYTE(pos, 0xc2 + 8 * instr->dst);
104 break;
105 case INSTR_SMULH_R:
106 EMIT_U64(pos, 0x8b4ce8f749c08b49 |
107 (((uint64_t)instr->src) << 40) |
108 (((uint64_t)instr->dst) << 16));
109 EMIT_BYTE(pos, 0xc2 + 8 * instr->dst);
110 break;
111 case INSTR_MUL_R:
112 EMIT_U32(pos, 0xc0af0f4d | (instr->dst << 27) | (instr->src << 24));
113 break;
114 case INSTR_SUB_R:
115 EMIT_U16(pos, 0x2b4d);
116 EMIT_BYTE(pos, 0xc0 | (instr->dst << 3) | instr->src);
117 break;
118 case INSTR_XOR_R:
119 EMIT_U16(pos, 0x334d);
120 EMIT_BYTE(pos, 0xc0 | (instr->dst << 3) | instr->src);
121 break;
122 case INSTR_ADD_RS:
123 EMIT_U32(pos, 0x00048d4f |
124 (instr->dst << 19) |
125 GEN_SIB(instr->imm32, instr->src, instr->dst) << 24);
126 break;
127 case INSTR_ROR_C:
128 EMIT_U32(pos, 0x00c8c149 | (instr->dst << 16) | (instr->imm32 << 24));
129 break;
130 case INSTR_ADD_C:
131 EMIT_U16(pos, 0x8149);
132 EMIT_BYTE(pos, 0xc0 | instr->dst);
133 EMIT_U32(pos, instr->imm32);
134 break;
135 case INSTR_XOR_C:
136 EMIT_U16(pos, 0x8149);
137 EMIT_BYTE(pos, 0xf0 | instr->dst);
138 EMIT_U32(pos, instr->imm32);
139 break;
140 case INSTR_TARGET:
141 target = pos; /* +2 */
142 EMIT_U32(pos, 0x440fff85);
143 EMIT_BYTE(pos, 0xf7);
144 break;
145 case INSTR_BRANCH:
146 EMIT_U64(pos, ((uint64_t)instr->imm32) << 32 | 0xc2f7f209);
147 EMIT_U16(pos, ((target - pos) << 8) | 0x74);
148 break;
149 default:
150 UNREACHABLE;
151 }
152 }
153 if (pos + sizeof x86_epilogue > code + COMP_CODE_SIZE)
154 return false;
155 EMIT(pos, x86_epilogue);
156 return hashx_vm_rx(code, COMP_CODE_SIZE);
157}
158
159#endif