mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
f6da559d5b
For upstreaming, we want functions we export either prefixed with "rb_" or made static. Historically we haven't been following this rule, so we were "leaking" a lot of symbols as `make leak-globals` would tell us. This change unifies everything YJIT into a single compilation unit, yjit.o, and makes everything unprefixed static to pass `make leak-globals`. This manual "unified build" setup is similar to that of vm.o. Having everything in one compilation unit allows static functions to be visible across YJIT files and removes the need for declarations in headers in some cases. Unnecessary declarations were removed. Other changes of note: - switched to MJIT_SYMBOL_EXPORT_BEGIN which indicates stuff as being off limits for native extensions - the first include of each YJIT file is change to be "internal.h" - undefined MAP_STACK before explicitly redefining it since it collide's with a definition in system headers. Consider renaming?
420 lines
16 KiB
C
420 lines
16 KiB
C
// For MAP_ANONYMOUS on GNU/Linux
|
|
#define _GNU_SOURCE 1
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "yjit_asm.c"
|
|
|
|
// Print the bytes in a code block
|
|
void print_bytes(codeblock_t* cb)
|
|
{
|
|
for (uint32_t i = 0; i < cb->write_pos; ++i)
|
|
{
|
|
printf("%02X", (int)cb->mem_block[i]);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
// Check that the code block contains the given sequence of bytes
|
|
void check_bytes(codeblock_t* cb, const char* bytes)
|
|
{
|
|
printf("checking encoding: %s\n", bytes);
|
|
|
|
size_t len = strlen(bytes);
|
|
assert (len % 2 == 0);
|
|
size_t num_bytes = len / 2;
|
|
|
|
if (cb->write_pos != num_bytes)
|
|
{
|
|
fprintf(stderr, "incorrect encoding length, expected %ld, got %d\n",
|
|
num_bytes,
|
|
cb->write_pos
|
|
);
|
|
printf("%s\n", bytes);
|
|
print_bytes(cb);
|
|
exit(-1);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < num_bytes; ++i)
|
|
{
|
|
char byte_str[] = {0, 0, 0, 0};
|
|
strncpy(byte_str, bytes + (2 * i), 2);
|
|
char* endptr;
|
|
long int byte = strtol(byte_str, &endptr, 16);
|
|
|
|
uint8_t cb_byte = cb->mem_block[i];
|
|
|
|
if (cb_byte != byte)
|
|
{
|
|
fprintf(stderr, "incorrect encoding at position %d, expected %02X, got %02X\n",
|
|
i,
|
|
(int)byte,
|
|
(int)cb_byte
|
|
);
|
|
printf("%s\n", bytes);
|
|
print_bytes(cb);
|
|
exit(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void run_assembler_tests()
|
|
{
|
|
printf("Running assembler tests\n");
|
|
|
|
codeblock_t cb_obj;
|
|
codeblock_t* cb = &cb_obj;
|
|
uint8_t* mem_block = alloc_exec_mem(4096);
|
|
cb_init(cb, mem_block, 4096);
|
|
|
|
// add
|
|
cb_set_pos(cb, 0); add(cb, CL, imm_opnd(3)); check_bytes(cb, "80C103");
|
|
cb_set_pos(cb, 0); add(cb, CL, BL); check_bytes(cb, "00D9");
|
|
cb_set_pos(cb, 0); add(cb, CL, SPL); check_bytes(cb, "4000E1");
|
|
cb_set_pos(cb, 0); add(cb, CX, BX); check_bytes(cb, "6601D9");
|
|
cb_set_pos(cb, 0); add(cb, RAX, RBX); check_bytes(cb, "4801D8");
|
|
cb_set_pos(cb, 0); add(cb, ECX, EDX); check_bytes(cb, "01D1");
|
|
cb_set_pos(cb, 0); add(cb, RDX, R14); check_bytes(cb, "4C01F2");
|
|
cb_set_pos(cb, 0); add(cb, mem_opnd(64, RAX, 0), RDX); check_bytes(cb, "480110");
|
|
cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 0)); check_bytes(cb, "480310");
|
|
cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 8)); check_bytes(cb, "48035008");
|
|
cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 255)); check_bytes(cb, "480390FF000000");
|
|
cb_set_pos(cb, 0); add(cb, mem_opnd(64, RAX, 127), imm_opnd(255)); check_bytes(cb, "4881407FFF000000");
|
|
cb_set_pos(cb, 0); add(cb, mem_opnd(32, RAX, 0), EDX); check_bytes(cb, "0110");
|
|
cb_set_pos(cb, 0); add(cb, RSP, imm_opnd(8)); check_bytes(cb, "4883C408");
|
|
cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(8)); check_bytes(cb, "83C108");
|
|
cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(255)); check_bytes(cb, "81C1FF000000");
|
|
|
|
// and
|
|
cb_set_pos(cb, 0); and(cb, EBP, R12D); check_bytes(cb, "4421E5");
|
|
cb_set_pos(cb, 0); and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08)); check_bytes(cb, "48832008");
|
|
|
|
// call
|
|
{
|
|
cb_set_pos(cb, 0);
|
|
uint32_t fn_label = cb_new_label(cb, "foo");
|
|
call_label(cb, fn_label);
|
|
cb_link_labels(cb);
|
|
check_bytes(cb, "E8FBFFFFFF");
|
|
}
|
|
cb_set_pos(cb, 0); call(cb, RAX); check_bytes(cb, "FFD0");
|
|
cb_set_pos(cb, 0); call(cb, mem_opnd(64, RSP, 8)); check_bytes(cb, "FF542408");
|
|
|
|
// cmovcc
|
|
cb_set_pos(cb, 0); cmovg(cb, ESI, EDI); check_bytes(cb, "0F4FF7");
|
|
cb_set_pos(cb, 0); cmovg(cb, ESI, mem_opnd(32, RBP, 12)); check_bytes(cb, "0F4F750C");
|
|
cb_set_pos(cb, 0); cmovl(cb, EAX, ECX); check_bytes(cb, "0F4CC1");
|
|
cb_set_pos(cb, 0); cmovl(cb, RBX, RBP); check_bytes(cb, "480F4CDD");
|
|
cb_set_pos(cb, 0); cmovle(cb, ESI, mem_opnd(32, RSP, 4)); check_bytes(cb, "0F4E742404");
|
|
|
|
// cmp
|
|
cb_set_pos(cb, 0); cmp(cb, CL, DL); check_bytes(cb, "38D1");
|
|
cb_set_pos(cb, 0); cmp(cb, ECX, EDI); check_bytes(cb, "39F9");
|
|
cb_set_pos(cb, 0); cmp(cb, RDX, mem_opnd(64, R12, 0)); check_bytes(cb, "493B1424");
|
|
cb_set_pos(cb, 0); cmp(cb, RAX, imm_opnd(2)); check_bytes(cb, "4883F802");
|
|
|
|
// cqo
|
|
cb_set_pos(cb, 0); cqo(cb); check_bytes(cb, "4899");
|
|
|
|
// div
|
|
/*
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.div(X86Opnd(EDX)); },
|
|
"F7F2"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.div(X86Opnd(32, RSP, -12)); },
|
|
"F77424F4"
|
|
);
|
|
*/
|
|
|
|
// jcc to label
|
|
{
|
|
cb_set_pos(cb, 0);
|
|
uint32_t loop_label = cb_new_label(cb, "loop");
|
|
jge_label(cb, loop_label);
|
|
cb_link_labels(cb);
|
|
check_bytes(cb, "0F8DFAFFFFFF");
|
|
}
|
|
{
|
|
cb_set_pos(cb, 0);
|
|
uint32_t loop_label = cb_new_label(cb, "loop");
|
|
jo_label(cb, loop_label);
|
|
cb_link_labels(cb);
|
|
check_bytes(cb, "0F80FAFFFFFF");
|
|
}
|
|
|
|
// jmp to label
|
|
{
|
|
cb_set_pos(cb, 0);
|
|
uint32_t loop_label = cb_new_label(cb, "loop");
|
|
jmp_label(cb, loop_label);
|
|
cb_link_labels(cb);
|
|
check_bytes(cb, "E9FBFFFFFF");
|
|
}
|
|
|
|
// jmp with RM operand
|
|
cb_set_pos(cb, 0); jmp_rm(cb, R12); check_bytes(cb, "41FFE4");
|
|
|
|
// lea
|
|
cb_set_pos(cb, 0); lea(cb, RDX, mem_opnd(64, RCX, 8)); check_bytes(cb, "488D5108");
|
|
cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 0)); check_bytes(cb, "488D0500000000");
|
|
cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 5)); check_bytes(cb, "488D0505000000");
|
|
cb_set_pos(cb, 0); lea(cb, RDI, mem_opnd(8, RIP, 5)); check_bytes(cb, "488D3D05000000");
|
|
|
|
// mov
|
|
cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(7)); check_bytes(cb, "B807000000");
|
|
cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(-3)); check_bytes(cb, "B8FDFFFFFF");
|
|
cb_set_pos(cb, 0); mov(cb, R15, imm_opnd(3)); check_bytes(cb, "49BF0300000000000000");
|
|
cb_set_pos(cb, 0); mov(cb, EAX, EBX); check_bytes(cb, "89D8");
|
|
cb_set_pos(cb, 0); mov(cb, EAX, ECX); check_bytes(cb, "89C8");
|
|
cb_set_pos(cb, 0); mov(cb, EDX, mem_opnd(32, RBX, 128)); check_bytes(cb, "8B9380000000");
|
|
/*
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.mov(X86Opnd(AL), X86Opnd(8, RCX, 0, 1, RDX)); },
|
|
"8A0411"
|
|
);
|
|
*/
|
|
cb_set_pos(cb, 0); mov(cb, CL, R9B); check_bytes(cb, "4488C9");
|
|
cb_set_pos(cb, 0); mov(cb, RBX, RAX); check_bytes(cb, "4889C3");
|
|
cb_set_pos(cb, 0); mov(cb, RDI, RBX); check_bytes(cb, "4889DF");
|
|
cb_set_pos(cb, 0); mov(cb, SIL, imm_opnd(11)); check_bytes(cb, "40B60B");
|
|
cb_set_pos(cb, 0); mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3)); check_bytes(cb, "C60424FD");
|
|
cb_set_pos(cb, 0); mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1)); check_bytes(cb, "48C7470801000000");
|
|
|
|
// movsx
|
|
cb_set_pos(cb, 0); movsx(cb, AX, AL); check_bytes(cb, "660FBEC0");
|
|
cb_set_pos(cb, 0); movsx(cb, EDX, AL); check_bytes(cb, "0FBED0");
|
|
cb_set_pos(cb, 0); movsx(cb, RAX, BL); check_bytes(cb, "480FBEC3");
|
|
cb_set_pos(cb, 0); movsx(cb, ECX, AX); check_bytes(cb, "0FBFC8");
|
|
cb_set_pos(cb, 0); movsx(cb, R11, CL); check_bytes(cb, "4C0FBED9");
|
|
cb_set_pos(cb, 0); movsx(cb, R10, mem_opnd(32, RSP, 12)); check_bytes(cb, "4C6354240C");
|
|
cb_set_pos(cb, 0); movsx(cb, RAX, mem_opnd(8, RSP, 0)); check_bytes(cb, "480FBE0424");
|
|
|
|
// neg
|
|
cb_set_pos(cb, 0); neg(cb, RAX); check_bytes(cb, "48F7D8");
|
|
|
|
// nop
|
|
cb_set_pos(cb, 0); nop(cb, 1); check_bytes(cb, "90");
|
|
|
|
// not
|
|
cb_set_pos(cb, 0); not(cb, AX); check_bytes(cb, "66F7D0");
|
|
cb_set_pos(cb, 0); not(cb, EAX); check_bytes(cb, "F7D0");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(64, R12, 0)); check_bytes(cb, "49F71424");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 301)); check_bytes(cb, "F794242D010000");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 0)); check_bytes(cb, "F71424");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 3)); check_bytes(cb, "F7542403");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RBP, 0)); check_bytes(cb, "F75500");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RBP, 13)); check_bytes(cb, "F7550D");
|
|
cb_set_pos(cb, 0); not(cb, RAX); check_bytes(cb, "48F7D0");
|
|
cb_set_pos(cb, 0); not(cb, R11); check_bytes(cb, "49F7D3");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RAX, 0)); check_bytes(cb, "F710");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSI, 0)); check_bytes(cb, "F716");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDI, 0)); check_bytes(cb, "F717");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, 55)); check_bytes(cb, "F75237");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, 1337)); check_bytes(cb, "F79239050000");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, -55)); check_bytes(cb, "F752C9");
|
|
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, -555)); check_bytes(cb, "F792D5FDFFFF");
|
|
/*
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RAX, 0, 1, RBX)); },
|
|
"F71418"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RAX, 0, 1, R12)); },
|
|
"42F71420"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 0, 1, R12)); },
|
|
"43F71427"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 5, 1, R12)); },
|
|
"43F7542705"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 5, 8, R12)); },
|
|
"43F754E705"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 5, 8, R13)); },
|
|
"43F754EF05"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R12, 5, 4, R9)); },
|
|
"43F7548C05"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R12, 301, 4, R9)); },
|
|
"43F7948C2D010000"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RAX, 5, 4, RDX)); },
|
|
"F7549005"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(64, RAX, 0, 2, RDX)); },
|
|
"48F71450"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RSP, 0, 1, RBX)); },
|
|
"F7141C"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RSP, 3, 1, RBX)); },
|
|
"F7541C03"
|
|
);
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RBP, 13, 1, RDX)); },
|
|
"F754150D"
|
|
);
|
|
*/
|
|
|
|
// or
|
|
cb_set_pos(cb, 0); or(cb, EDX, ESI); check_bytes(cb, "09F2");
|
|
|
|
// pop
|
|
cb_set_pos(cb, 0); pop(cb, RAX); check_bytes(cb, "58");
|
|
cb_set_pos(cb, 0); pop(cb, RBX); check_bytes(cb, "5B");
|
|
cb_set_pos(cb, 0); pop(cb, RSP); check_bytes(cb, "5C");
|
|
cb_set_pos(cb, 0); pop(cb, RBP); check_bytes(cb, "5D");
|
|
cb_set_pos(cb, 0); pop(cb, R12); check_bytes(cb, "415C");
|
|
cb_set_pos(cb, 0); pop(cb, mem_opnd(64, RAX, 0)); check_bytes(cb, "8F00");
|
|
cb_set_pos(cb, 0); pop(cb, mem_opnd(64, R8, 0)); check_bytes(cb, "418F00");
|
|
cb_set_pos(cb, 0); pop(cb, mem_opnd(64, R8, 3)); check_bytes(cb, "418F4003");
|
|
cb_set_pos(cb, 0); pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3)); check_bytes(cb, "8F44C803");
|
|
cb_set_pos(cb, 0); pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3)); check_bytes(cb, "418F44C803");
|
|
|
|
// push
|
|
cb_set_pos(cb, 0); push(cb, RAX); check_bytes(cb, "50");
|
|
cb_set_pos(cb, 0); push(cb, RBX); check_bytes(cb, "53");
|
|
cb_set_pos(cb, 0); push(cb, R12); check_bytes(cb, "4154");
|
|
cb_set_pos(cb, 0); push(cb, mem_opnd(64, RAX, 0)); check_bytes(cb, "FF30");
|
|
cb_set_pos(cb, 0); push(cb, mem_opnd(64, R8, 0)); check_bytes(cb, "41FF30");
|
|
cb_set_pos(cb, 0); push(cb, mem_opnd(64, R8, 3)); check_bytes(cb, "41FF7003");
|
|
cb_set_pos(cb, 0); push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3)); check_bytes(cb, "FF74C803");
|
|
cb_set_pos(cb, 0); push(cb, mem_opnd_sib(64, R8, RCX, 8, 3)); check_bytes(cb, "41FF74C803");
|
|
|
|
// ret
|
|
cb_set_pos(cb, 0); ret(cb); check_bytes(cb, "C3");
|
|
|
|
// sal
|
|
cb_set_pos(cb, 0); sal(cb, CX, imm_opnd(1)); check_bytes(cb, "66D1E1");
|
|
cb_set_pos(cb, 0); sal(cb, ECX, imm_opnd(1)); check_bytes(cb, "D1E1");
|
|
cb_set_pos(cb, 0); sal(cb, EBP, imm_opnd(5)); check_bytes(cb, "C1E505");
|
|
cb_set_pos(cb, 0); sal(cb, mem_opnd(32, RSP, 68), imm_opnd(1)); check_bytes(cb, "D1642444");
|
|
|
|
// sar
|
|
cb_set_pos(cb, 0); sar(cb, EDX, imm_opnd(1)); check_bytes(cb, "D1FA");
|
|
|
|
// shr
|
|
cb_set_pos(cb, 0); shr(cb, R14, imm_opnd(7)); check_bytes(cb, "49C1EE07");
|
|
|
|
/*
|
|
// sqrtsd
|
|
test(
|
|
delegate void (CodeBlock cb) { cb.sqrtsd(X86Opnd(XMM2), X86Opnd(XMM6)); },
|
|
"F20F51D6"
|
|
);
|
|
*/
|
|
|
|
// sub
|
|
cb_set_pos(cb, 0); sub(cb, EAX, imm_opnd(1)); check_bytes(cb, "83E801");
|
|
cb_set_pos(cb, 0); sub(cb, RAX, imm_opnd(2)); check_bytes(cb, "4883E802");
|
|
|
|
// test
|
|
cb_set_pos(cb, 0); test(cb, AL, AL); check_bytes(cb, "84C0");
|
|
cb_set_pos(cb, 0); test(cb, AX, AX); check_bytes(cb, "6685C0");
|
|
cb_set_pos(cb, 0); test(cb, CL, imm_opnd(8)); check_bytes(cb, "F6C108");
|
|
cb_set_pos(cb, 0); test(cb, DL, imm_opnd(7)); check_bytes(cb, "F6C207");
|
|
cb_set_pos(cb, 0); test(cb, RCX, imm_opnd(8)); check_bytes(cb, "F6C108");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RDX, 8), imm_opnd(8)); check_bytes(cb, "F6420808");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RDX, 8), imm_opnd(255)); check_bytes(cb, "F64208FF");
|
|
cb_set_pos(cb, 0); test(cb, DX, imm_opnd(0xFFFF)); check_bytes(cb, "66F7C2FFFF");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(16, RDX, 8), imm_opnd(0xFFFF)); check_bytes(cb, "66F74208FFFF");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, 0), imm_opnd(1)); check_bytes(cb, "F60601");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, 16), imm_opnd(1)); check_bytes(cb, "F6461001");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, -16), imm_opnd(1)); check_bytes(cb, "F646F001");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(32, RSI, 64), EAX); check_bytes(cb, "854640");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(64, RDI, 42), RAX); check_bytes(cb, "4885472A");
|
|
cb_set_pos(cb, 0); test(cb, RAX, RAX); check_bytes(cb, "4885C0");
|
|
cb_set_pos(cb, 0); test(cb, RAX, RSI); check_bytes(cb, "4885F0");
|
|
cb_set_pos(cb, 0); test(cb, mem_opnd(64, RSI, 64), imm_opnd(~0x08)); check_bytes(cb, "48F74640F7FFFFFF");
|
|
|
|
// xchg
|
|
cb_set_pos(cb, 0); xchg(cb, RAX, RCX); check_bytes(cb, "4891");
|
|
cb_set_pos(cb, 0); xchg(cb, RAX, R13); check_bytes(cb, "4995");
|
|
cb_set_pos(cb, 0); xchg(cb, RCX, RBX); check_bytes(cb, "4887D9");
|
|
cb_set_pos(cb, 0); xchg(cb, R9, R15); check_bytes(cb, "4D87F9");
|
|
|
|
// xor
|
|
cb_set_pos(cb, 0); xor(cb, EAX, EAX); check_bytes(cb, "31C0");
|
|
|
|
printf("Assembler tests done\n");
|
|
}
|
|
|
|
void assert_equal(expected, actual)
|
|
{
|
|
if (expected != actual) {
|
|
fprintf(stderr, "expected %d, got %d\n", expected, actual);
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
void run_runtime_tests()
|
|
{
|
|
printf("Running runtime tests\n");
|
|
|
|
codeblock_t codeblock;
|
|
codeblock_t* cb = &codeblock;
|
|
|
|
uint8_t* mem_block = alloc_exec_mem(4096);
|
|
cb_init(cb, mem_block, 4096);
|
|
|
|
int (*function)(void);
|
|
function = (int (*)(void))mem_block;
|
|
|
|
#define TEST(BODY) cb_set_pos(cb, 0); BODY ret(cb); assert_equal(7, function());
|
|
|
|
// add
|
|
TEST({ mov(cb, RAX, imm_opnd(0)); add(cb, RAX, imm_opnd(7)); })
|
|
TEST({ mov(cb, RAX, imm_opnd(0)); mov(cb, RCX, imm_opnd(7)); add(cb, RAX, RCX); })
|
|
|
|
// and
|
|
TEST({ mov(cb, RAX, imm_opnd(31)); and(cb, RAX, imm_opnd(7)); })
|
|
TEST({ mov(cb, RAX, imm_opnd(31)); mov(cb, RCX, imm_opnd(7)); and(cb, RAX, RCX); })
|
|
|
|
// or
|
|
TEST({ mov(cb, RAX, imm_opnd(3)); or(cb, RAX, imm_opnd(4)); })
|
|
TEST({ mov(cb, RAX, imm_opnd(3)); mov(cb, RCX, imm_opnd(4)); or(cb, RAX, RCX); })
|
|
|
|
// push/pop
|
|
TEST({ mov(cb, RCX, imm_opnd(7)); push(cb, RCX); pop(cb, RAX); })
|
|
|
|
// shr
|
|
TEST({ mov(cb, RAX, imm_opnd(31)); shr(cb, RAX, imm_opnd(2)); })
|
|
|
|
// sub
|
|
TEST({ mov(cb, RAX, imm_opnd(12)); sub(cb, RAX, imm_opnd(5)); })
|
|
TEST({ mov(cb, RAX, imm_opnd(12)); mov(cb, RCX, imm_opnd(5)); sub(cb, RAX, RCX); })
|
|
|
|
// xor
|
|
TEST({ mov(cb, RAX, imm_opnd(13)); xor(cb, RAX, imm_opnd(10)); })
|
|
TEST({ mov(cb, RAX, imm_opnd(13)); mov(cb, RCX, imm_opnd(10)); xor(cb, RAX, RCX); })
|
|
|
|
#undef TEST
|
|
|
|
printf("Runtime tests done\n");
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
run_assembler_tests();
|
|
run_runtime_tests();
|
|
|
|
return 0;
|
|
}
|