13 static void rb_bug(
const char *message, ...)
16 va_start(args, message);
17 vfprintf(stderr, message, args);
27 for (uint32_t i = 0; i < cb->write_pos; ++i)
29 printf(
"%02X", (
int)*cb_get_ptr(cb, i));
36 void check_bytes(
codeblock_t* cb,
const char* bytes)
38 printf(
"checking encoding: %s\n", bytes);
40 size_t len = strlen(bytes);
41 assert (len % 2 == 0);
42 size_t num_bytes = len / 2;
44 if (cb->write_pos != num_bytes)
46 fprintf(stderr,
"incorrect encoding length, expected %ld, got %d\n",
50 printf(
"%s\n", bytes);
55 for (uint32_t i = 0; i < num_bytes; ++i)
57 char byte_str[] = {0, 0, 0, 0};
58 strncpy(byte_str, bytes + (2 * i), 2);
60 long int byte = strtol(byte_str, &endptr, 16);
62 uint8_t cb_byte = *cb_get_ptr(cb, i);
66 fprintf(stderr,
"incorrect encoding at position %d, expected %02X, got %02X\n",
71 printf(
"%s\n", bytes);
78 void run_assembler_tests(
void)
80 printf(
"Running assembler tests\n");
84 uint8_t* mem_block = alloc_exec_mem(4096);
85 cb_init(cb, mem_block, 4096);
88 cb_set_pos(cb, 0); add(cb, CL, imm_opnd(3)); check_bytes(cb,
"80C103");
89 cb_set_pos(cb, 0); add(cb, CL, BL); check_bytes(cb,
"00D9");
90 cb_set_pos(cb, 0); add(cb, CL, SPL); check_bytes(cb,
"4000E1");
91 cb_set_pos(cb, 0); add(cb, CX, BX); check_bytes(cb,
"6601D9");
92 cb_set_pos(cb, 0); add(cb, RAX, RBX); check_bytes(cb,
"4801D8");
93 cb_set_pos(cb, 0); add(cb, ECX, EDX); check_bytes(cb,
"01D1");
94 cb_set_pos(cb, 0); add(cb, RDX, R14); check_bytes(cb,
"4C01F2");
95 cb_set_pos(cb, 0); add(cb, mem_opnd(64, RAX, 0), RDX); check_bytes(cb,
"480110");
96 cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 0)); check_bytes(cb,
"480310");
97 cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 8)); check_bytes(cb,
"48035008");
98 cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 255)); check_bytes(cb,
"480390FF000000");
99 cb_set_pos(cb, 0); add(cb, mem_opnd(64, RAX, 127), imm_opnd(255)); check_bytes(cb,
"4881407FFF000000");
100 cb_set_pos(cb, 0); add(cb, mem_opnd(32, RAX, 0), EDX); check_bytes(cb,
"0110");
101 cb_set_pos(cb, 0); add(cb, RSP, imm_opnd(8)); check_bytes(cb,
"4883C408");
102 cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(8)); check_bytes(cb,
"83C108");
103 cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(255)); check_bytes(cb,
"81C1FF000000");
106 cb_set_pos(cb, 0); and(cb, EBP, R12D); check_bytes(cb,
"4421E5");
107 cb_set_pos(cb, 0); and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08)); check_bytes(cb,
"48832008");
112 uint32_t fn_label = cb_new_label(cb,
"foo");
113 call_label(cb, fn_label);
115 check_bytes(cb,
"E8FBFFFFFF");
117 cb_set_pos(cb, 0); call(cb, RAX); check_bytes(cb,
"FFD0");
118 cb_set_pos(cb, 0); call(cb, mem_opnd(64, RSP, 8)); check_bytes(cb,
"FF542408");
121 cb_set_pos(cb, 0); cmovg(cb, ESI, EDI); check_bytes(cb,
"0F4FF7");
122 cb_set_pos(cb, 0); cmovg(cb, ESI, mem_opnd(32, RBP, 12)); check_bytes(cb,
"0F4F750C");
123 cb_set_pos(cb, 0); cmovl(cb, EAX, ECX); check_bytes(cb,
"0F4CC1");
124 cb_set_pos(cb, 0); cmovl(cb, RBX, RBP); check_bytes(cb,
"480F4CDD");
125 cb_set_pos(cb, 0); cmovle(cb, ESI, mem_opnd(32, RSP, 4)); check_bytes(cb,
"0F4E742404");
128 cb_set_pos(cb, 0); cmp(cb, CL, DL); check_bytes(cb,
"38D1");
129 cb_set_pos(cb, 0); cmp(cb, ECX, EDI); check_bytes(cb,
"39F9");
130 cb_set_pos(cb, 0); cmp(cb, RDX, mem_opnd(64, R12, 0)); check_bytes(cb,
"493B1424");
131 cb_set_pos(cb, 0); cmp(cb, RAX, imm_opnd(2)); check_bytes(cb,
"4883F802");
134 cb_set_pos(cb, 0); cqo(cb); check_bytes(cb,
"4899");
151 uint32_t loop_label = cb_new_label(cb,
"loop");
152 jge_label(cb, loop_label);
154 check_bytes(cb,
"0F8DFAFFFFFF");
158 uint32_t loop_label = cb_new_label(cb,
"loop");
159 jo_label(cb, loop_label);
161 check_bytes(cb,
"0F80FAFFFFFF");
167 uint32_t loop_label = cb_new_label(cb,
"loop");
168 jmp_label(cb, loop_label);
170 check_bytes(cb,
"E9FBFFFFFF");
174 cb_set_pos(cb, 0); jmp_rm(cb, R12); check_bytes(cb,
"41FFE4");
177 cb_set_pos(cb, 0); lea(cb, RDX, mem_opnd(64, RCX, 8)); check_bytes(cb,
"488D5108");
178 cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 0)); check_bytes(cb,
"488D0500000000");
179 cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 5)); check_bytes(cb,
"488D0505000000");
180 cb_set_pos(cb, 0); lea(cb, RDI, mem_opnd(8, RIP, 5)); check_bytes(cb,
"488D3D05000000");
183 cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(7)); check_bytes(cb,
"B807000000");
184 cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(-3)); check_bytes(cb,
"B8FDFFFFFF");
185 cb_set_pos(cb, 0); mov(cb, R15, imm_opnd(3)); check_bytes(cb,
"41BF03000000");
186 cb_set_pos(cb, 0); mov(cb, EAX, EBX); check_bytes(cb,
"89D8");
187 cb_set_pos(cb, 0); mov(cb, EAX, ECX); check_bytes(cb,
"89C8");
188 cb_set_pos(cb, 0); mov(cb, EDX, mem_opnd(32, RBX, 128)); check_bytes(cb,
"8B9380000000");
191 cb_set_pos(cb, 0); mov(cb, R8, imm_opnd(0x34)); check_bytes(cb,
"41B834000000");
192 cb_set_pos(cb, 0); mov(cb, R8, imm_opnd(0x80000000)); check_bytes(cb,
"49B80000008000000000");
193 cb_set_pos(cb, 0); mov(cb, R8, imm_opnd(-1)); check_bytes(cb,
"49B8FFFFFFFFFFFFFFFF");
195 cb_set_pos(cb, 0); mov(cb, RAX, imm_opnd(0x34)); check_bytes(cb,
"B834000000");
196 cb_set_pos(cb, 0); mov(cb, RAX, imm_opnd(0x80000000)); check_bytes(cb,
"48B80000008000000000");
197 cb_set_pos(cb, 0); mov(cb, RAX, imm_opnd(-52)); check_bytes(cb,
"48B8CCFFFFFFFFFFFFFF");
198 cb_set_pos(cb, 0); mov(cb, RAX, imm_opnd(-1)); check_bytes(cb,
"48B8FFFFFFFFFFFFFFFF");
205 cb_set_pos(cb, 0); mov(cb, CL, R9B); check_bytes(cb,
"4488C9");
206 cb_set_pos(cb, 0); mov(cb, RBX, RAX); check_bytes(cb,
"4889C3");
207 cb_set_pos(cb, 0); mov(cb, RDI, RBX); check_bytes(cb,
"4889DF");
208 cb_set_pos(cb, 0); mov(cb, SIL, imm_opnd(11)); check_bytes(cb,
"40B60B");
209 cb_set_pos(cb, 0); mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3)); check_bytes(cb,
"C60424FD");
210 cb_set_pos(cb, 0); mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1)); check_bytes(cb,
"48C7470801000000");
213 cb_set_pos(cb, 0); movsx(cb, AX, AL); check_bytes(cb,
"660FBEC0");
214 cb_set_pos(cb, 0); movsx(cb, EDX, AL); check_bytes(cb,
"0FBED0");
215 cb_set_pos(cb, 0); movsx(cb, RAX, BL); check_bytes(cb,
"480FBEC3");
216 cb_set_pos(cb, 0); movsx(cb, ECX, AX); check_bytes(cb,
"0FBFC8");
217 cb_set_pos(cb, 0); movsx(cb, R11, CL); check_bytes(cb,
"4C0FBED9");
218 cb_set_pos(cb, 0); movsx(cb, R10, mem_opnd(32, RSP, 12)); check_bytes(cb,
"4C6354240C");
219 cb_set_pos(cb, 0); movsx(cb, RAX, mem_opnd(8, RSP, 0)); check_bytes(cb,
"480FBE0424");
222 cb_set_pos(cb, 0); neg(cb, RAX); check_bytes(cb,
"48F7D8");
225 cb_set_pos(cb, 0); nop(cb, 1); check_bytes(cb,
"90");
228 cb_set_pos(cb, 0); not(cb, AX); check_bytes(cb,
"66F7D0");
229 cb_set_pos(cb, 0); not(cb, EAX); check_bytes(cb,
"F7D0");
230 cb_set_pos(cb, 0); not(cb, mem_opnd(64, R12, 0)); check_bytes(cb,
"49F71424");
231 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 301)); check_bytes(cb,
"F794242D010000");
232 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 0)); check_bytes(cb,
"F71424");
233 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 3)); check_bytes(cb,
"F7542403");
234 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RBP, 0)); check_bytes(cb,
"F75500");
235 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RBP, 13)); check_bytes(cb,
"F7550D");
236 cb_set_pos(cb, 0); not(cb, RAX); check_bytes(cb,
"48F7D0");
237 cb_set_pos(cb, 0); not(cb, R11); check_bytes(cb,
"49F7D3");
238 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RAX, 0)); check_bytes(cb,
"F710");
239 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSI, 0)); check_bytes(cb,
"F716");
240 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDI, 0)); check_bytes(cb,
"F717");
241 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, 55)); check_bytes(cb,
"F75237");
242 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, 1337)); check_bytes(cb,
"F79239050000");
243 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, -55)); check_bytes(cb,
"F752C9");
244 cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, -555)); check_bytes(cb,
"F792D5FDFFFF");
301 cb_set_pos(cb, 0); or(cb, EDX, ESI); check_bytes(cb,
"09F2");
304 cb_set_pos(cb, 0); pop(cb, RAX); check_bytes(cb,
"58");
305 cb_set_pos(cb, 0); pop(cb, RBX); check_bytes(cb,
"5B");
306 cb_set_pos(cb, 0); pop(cb, RSP); check_bytes(cb,
"5C");
307 cb_set_pos(cb, 0); pop(cb, RBP); check_bytes(cb,
"5D");
308 cb_set_pos(cb, 0); pop(cb, R12); check_bytes(cb,
"415C");
309 cb_set_pos(cb, 0); pop(cb, mem_opnd(64, RAX, 0)); check_bytes(cb,
"8F00");
310 cb_set_pos(cb, 0); pop(cb, mem_opnd(64, R8, 0)); check_bytes(cb,
"418F00");
311 cb_set_pos(cb, 0); pop(cb, mem_opnd(64, R8, 3)); check_bytes(cb,
"418F4003");
312 cb_set_pos(cb, 0); pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3)); check_bytes(cb,
"8F44C803");
313 cb_set_pos(cb, 0); pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3)); check_bytes(cb,
"418F44C803");
316 cb_set_pos(cb, 0); push(cb, RAX); check_bytes(cb,
"50");
317 cb_set_pos(cb, 0); push(cb, RBX); check_bytes(cb,
"53");
318 cb_set_pos(cb, 0); push(cb, R12); check_bytes(cb,
"4154");
319 cb_set_pos(cb, 0); push(cb, mem_opnd(64, RAX, 0)); check_bytes(cb,
"FF30");
320 cb_set_pos(cb, 0); push(cb, mem_opnd(64, R8, 0)); check_bytes(cb,
"41FF30");
321 cb_set_pos(cb, 0); push(cb, mem_opnd(64, R8, 3)); check_bytes(cb,
"41FF7003");
322 cb_set_pos(cb, 0); push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3)); check_bytes(cb,
"FF74C803");
323 cb_set_pos(cb, 0); push(cb, mem_opnd_sib(64, R8, RCX, 8, 3)); check_bytes(cb,
"41FF74C803");
326 cb_set_pos(cb, 0); ret(cb); check_bytes(cb,
"C3");
329 cb_set_pos(cb, 0); sal(cb, CX, imm_opnd(1)); check_bytes(cb,
"66D1E1");
330 cb_set_pos(cb, 0); sal(cb, ECX, imm_opnd(1)); check_bytes(cb,
"D1E1");
331 cb_set_pos(cb, 0); sal(cb, EBP, imm_opnd(5)); check_bytes(cb,
"C1E505");
332 cb_set_pos(cb, 0); sal(cb, mem_opnd(32, RSP, 68), imm_opnd(1)); check_bytes(cb,
"D1642444");
335 cb_set_pos(cb, 0); sar(cb, EDX, imm_opnd(1)); check_bytes(cb,
"D1FA");
338 cb_set_pos(cb, 0); shr(cb, R14, imm_opnd(7)); check_bytes(cb,
"49C1EE07");
349 cb_set_pos(cb, 0); sub(cb, EAX, imm_opnd(1)); check_bytes(cb,
"83E801");
350 cb_set_pos(cb, 0); sub(cb, RAX, imm_opnd(2)); check_bytes(cb,
"4883E802");
353 cb_set_pos(cb, 0); test(cb, AL, AL); check_bytes(cb,
"84C0");
354 cb_set_pos(cb, 0); test(cb, AX, AX); check_bytes(cb,
"6685C0");
355 cb_set_pos(cb, 0); test(cb, CL, imm_opnd(8)); check_bytes(cb,
"F6C108");
356 cb_set_pos(cb, 0); test(cb, DL, imm_opnd(7)); check_bytes(cb,
"F6C207");
357 cb_set_pos(cb, 0); test(cb, RCX, imm_opnd(8)); check_bytes(cb,
"F6C108");
358 cb_set_pos(cb, 0); test(cb, mem_opnd(8, RDX, 8), imm_opnd(8)); check_bytes(cb,
"F6420808");
359 cb_set_pos(cb, 0); test(cb, mem_opnd(8, RDX, 8), imm_opnd(255)); check_bytes(cb,
"F64208FF");
360 cb_set_pos(cb, 0); test(cb, DX, imm_opnd(0xFFFF)); check_bytes(cb,
"66F7C2FFFF");
361 cb_set_pos(cb, 0); test(cb, mem_opnd(16, RDX, 8), imm_opnd(0xFFFF)); check_bytes(cb,
"66F74208FFFF");
362 cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, 0), imm_opnd(1)); check_bytes(cb,
"F60601");
363 cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, 16), imm_opnd(1)); check_bytes(cb,
"F6461001");
364 cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, -16), imm_opnd(1)); check_bytes(cb,
"F646F001");
365 cb_set_pos(cb, 0); test(cb, mem_opnd(32, RSI, 64), EAX); check_bytes(cb,
"854640");
366 cb_set_pos(cb, 0); test(cb, mem_opnd(64, RDI, 42), RAX); check_bytes(cb,
"4885472A");
367 cb_set_pos(cb, 0); test(cb, RAX, RAX); check_bytes(cb,
"4885C0");
368 cb_set_pos(cb, 0); test(cb, RAX, RSI); check_bytes(cb,
"4885F0");
369 cb_set_pos(cb, 0); test(cb, mem_opnd(64, RSI, 64), imm_opnd(~0x08)); check_bytes(cb,
"48F74640F7FFFFFF");
372 cb_set_pos(cb, 0); xchg(cb, RAX, RCX); check_bytes(cb,
"4891");
373 cb_set_pos(cb, 0); xchg(cb, RAX, R13); check_bytes(cb,
"4995");
374 cb_set_pos(cb, 0); xchg(cb, RCX, RBX); check_bytes(cb,
"4887D9");
375 cb_set_pos(cb, 0); xchg(cb, R9, R15); check_bytes(cb,
"4D87F9");
378 cb_set_pos(cb, 0); xor(cb, EAX, EAX); check_bytes(cb,
"31C0");
380 printf(
"Assembler tests done\n");
383 void assert_equal(
int expected,
int actual)
385 if (expected != actual) {
386 fprintf(stderr,
"expected %d, got %d\n", expected, actual);
391 void run_runtime_tests(
void)
393 printf(
"Running runtime tests\n");
398 uint8_t* mem_block = alloc_exec_mem(4096);
399 cb_init(cb, mem_block, 4096);
401 int (*
function)(void);
402 function = (int (*)(void))mem_block;
404 #define TEST(BODY) cb_set_pos(cb, 0); BODY ret(cb); cb_mark_all_executable(cb); assert_equal(7, function());
407 TEST({ mov(cb, RAX, imm_opnd(0)); add(cb, RAX, imm_opnd(7)); })
408 TEST({ mov(cb, RAX, imm_opnd(0)); mov(cb, RCX, imm_opnd(7)); add(cb, RAX, RCX); })
411 TEST({ mov(cb, RAX, imm_opnd(31)); and(cb, RAX, imm_opnd(7)); })
412 TEST({ mov(cb, RAX, imm_opnd(31)); mov(cb, RCX, imm_opnd(7)); and(cb, RAX, RCX); })
415 TEST({ mov(cb, RAX, imm_opnd(3)); or(cb, RAX, imm_opnd(4)); })
416 TEST({ mov(cb, RAX, imm_opnd(3)); mov(cb, RCX, imm_opnd(4)); or(cb, RAX, RCX); })
419 TEST({ mov(cb, RCX, imm_opnd(7)); push(cb, RCX); pop(cb, RAX); })
422 TEST({ mov(cb, RAX, imm_opnd(31)); shr(cb, RAX, imm_opnd(2)); })
425 TEST({ mov(cb, RAX, imm_opnd(12)); sub(cb, RAX, imm_opnd(5)); })
426 TEST({ mov(cb, RAX, imm_opnd(12)); mov(cb, RCX, imm_opnd(5)); sub(cb, RAX, RCX); })
429 TEST({ mov(cb, RAX, imm_opnd(13)); xor(cb, RAX, imm_opnd(10)); })
430 TEST({ mov(cb, RAX, imm_opnd(13)); mov(cb, RCX, imm_opnd(10)); xor(cb, RAX, RCX); })
434 printf(
"Runtime tests done\n");
437 int main(
int argc,
char** argv)
439 run_assembler_tests();
void rb_bug(const char *fmt,...)
Interpreter panic switch.