pslang/libs/jit/source/arch/linux_x86_64/instruction_builder.cpp

609 lines
19 KiB
C++

#include <pslang/jit/arch/linux_x86_64/instruction_builder.hpp>
#include <pslang/jit/helpers.hpp>
namespace pslang::jit::linux_x86_64
{
namespace
{
// Construct the REX prefix:
// W (0/1) - enable 64-bit operand
// R (0/1) - extend ModR/M reg field
// X (0/1) - extend the SIB index field
// B (0/1) - extend the base or opcode register field
std::uint8_t rex(std::uint8_t W, std::uint8_t R, std::uint8_t X, std::uint8_t B)
{
check_bits(W, 1, "REX prefix W");
check_bits(R, 1, "REX prefix R");
check_bits(X, 1, "REX prefix X");
check_bits(B, 1, "REX prefix B");
return 0x40u | (W << 3) | (R << 2) | (X << 1) | B;
}
// Same, but using `reg` enum instead - passes the highest (#3) bit of
// the register number to rex()
std::uint8_t rex(std::uint8_t W, reg R, reg X, reg B)
{
return rex(W, std::uint8_t(R) >> 3, std::uint8_t(X) >> 3, std::uint8_t(B) >> 3);
}
// Memory
static constexpr std::uint8_t MOD_MEM = 0;
// Memory + 8-bit offset
static constexpr std::uint8_t MOD_MEM8 = 1;
// Memory + 32-bit offset
static constexpr std::uint8_t MOD_MEM32 = 2;
// Register
static constexpr std::uint8_t MOD_REG = 3;
std::uint8_t modrm(std::uint8_t mod, std::uint8_t reg, std::uint8_t rm)
{
check_bits(mod, 2, "ModR/M mod");
check_bits(reg, 3, "ModR/M reg");
check_bits(rm, 3, "ModR/M rm");
return (mod << 6) | (reg << 3) | rm;
}
std::uint8_t modrm(std::uint8_t mod, reg reg, std::uint8_t rm)
{
return modrm(mod, (std::uint8_t)(reg) & 0b111, rm);
}
std::uint8_t modrm(std::uint8_t mod, std::uint8_t reg_, reg rm)
{
return modrm(mod, reg_, (std::uint8_t)(rm) & 0b111);
}
std::uint8_t modrm(std::uint8_t mod, reg reg_, reg rm)
{
return modrm(mod, (std::uint8_t)(reg_) & 0b111, (std::uint8_t)(rm) & 0b111);
}
static constexpr std::uint8_t SIB_NOINDEX = 4;
std::uint8_t sib(std::uint8_t scale, std::uint8_t index, std::uint8_t base)
{
check_bits(scale, 2, "SIB scale");
check_bits(index, 3, "SIB index");
check_bits(base, 3, "SIB base");
return (scale << 6) | (index << 3) | base;
}
std::uint8_t sib(std::uint8_t scale, reg reg_, std::uint8_t base)
{
return sib(scale, (std::uint8_t)(reg_) & 0b111, base);
}
std::uint8_t sib(std::uint8_t scale, std::uint8_t reg_, reg base)
{
return sib(scale, reg_, (std::uint8_t)(base) & 0b111);
}
std::uint8_t sib(std::uint8_t scale, reg reg_, reg base)
{
return sib(scale, (std::uint8_t)(reg_) & 0b111, (std::uint8_t)(base) & 0b111);
}
std::uint8_t opcode_add_reg(std::uint8_t opcode, reg reg)
{
return opcode + ((std::uint8_t)(reg) & 0b111);
}
bool need_sib(reg reg)
{
return ((std::uint8_t)(reg) & 0b111) == 4;
}
std::uint8_t vex(std::uint8_t R, std::uint8_t X, std::uint8_t B, std::uint8_t MMMMM)
{
check_bits(R, 1, "VEX prefix R");
check_bits(X, 1, "VEX prefix X");
check_bits(B, 1, "VEX prefix B");
check_bits(MMMMM, 1, "VEX prefix m-mmmm");
return ((1 - R) << 7) | ((1 - X) << 6) | ((1 - B) << 5) | MMMMM;
}
std::uint8_t vex(reg R, reg X, reg B, std::uint8_t MMMMM)
{
return rex(std::uint8_t(R) >> 3, std::uint8_t(X) >> 3, std::uint8_t(B) >> 3, MMMMM);
}
}
void instruction_builder::nop()
{
do_push(0x90_ub);
}
void instruction_builder::ret(std::uint16_t count)
{
if (count == 0)
do_push(0xc3_ub);
else
do_push(0xc2_ub, count);
}
void instruction_builder::add_imm(reg reg, std::int32_t value)
{
if (value >= -128 && value <= 127)
do_push(rex(1, {}, {}, reg), 0x83_ub, modrm(MOD_REG, 0, reg), (std::int8_t)value);
else
do_push(rex(1, {}, {}, reg), 0x81_ub, modrm(MOD_REG, 0, reg), value);
}
void instruction_builder::sub_imm(reg reg, std::int32_t value)
{
if (value >= -128 && value <= 127)
do_push(rex(1, {}, {}, reg), 0x83_ub, modrm(MOD_REG, 5, reg), (std::int8_t)value);
else
do_push(rex(1, {}, {}, reg), 0x81_ub, modrm(MOD_REG, 5, reg), value);
}
void instruction_builder::movzd(std::uint32_t value, reg reg_dst)
{
if (((std::uint8_t)(reg_dst) & 0b1000) != 0)
do_push(rex(0, {}, {}, reg_dst), opcode_add_reg(0xb8, reg_dst), value);
else
do_push(opcode_add_reg(0xb8, reg_dst), value);
}
void instruction_builder::movsd(std::int32_t value, reg reg_dst)
{
do_push(rex(1, {}, {}, reg_dst), 0xc7_ub, modrm(MOD_REG, 0, reg_dst), value);
}
void instruction_builder::movzx_8(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0xb6_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::movzx_16(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0xb7_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::movsx_8(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0xbe_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::movsx_16(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0xbf_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::movsx_32(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x63_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mov(std::uint64_t value, reg reg_dst)
{
do_push(rex(1, {}, {}, reg_dst), opcode_add_reg(0xb8, reg_dst), value);
}
void instruction_builder::mov(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x8b_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mov_gpr_to_xmm(reg reg_src, reg reg_dst)
{
do_push(0x66_ub, rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x6e_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mov_gpr_to_xmm_32(reg reg_src, reg reg_dst)
{
do_push(0x66_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x6e_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mov_read(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(rex(1, reg_dst, {}, reg_addr), 0x8b_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(1, reg_dst, {}, reg_addr), 0x8b_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::mov_read_32(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(rex(0, reg_dst, {}, reg_addr), 0x8b_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(0, reg_dst, {}, reg_addr), 0x8b_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::mov_read_16(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(0x66_ub, rex(0, reg_dst, {}, reg_addr), 0x8b_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(0x66_ub, rex(0, reg_dst, {}, reg_addr), 0x8b_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::mov_read_8(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(rex(0, reg_dst, {}, reg_addr), 0x8a_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(0, reg_dst, {}, reg_addr), 0x8a_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::mov_read_rip(std::int32_t offset, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, {}), 0x8b_ub, modrm(0, reg_dst, 0b101), offset);
}
void instruction_builder::mov_read_rip_prev(std::int32_t offset, reg reg_dst)
{
mov_read_rip(offset - 7, reg_dst);
}
void instruction_builder::mov_write(reg reg_src, reg reg_addr, std::int32_t offset)
{
if (need_sib(reg_addr))
do_push(rex(1, reg_src, {}, reg_addr), 0x89_ub, modrm(MOD_MEM32, reg_src, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(1, reg_src, {}, reg_addr), 0x89_ub, modrm(MOD_MEM32, reg_src, reg_addr), offset);
}
void instruction_builder::mov_write_32(reg reg_src, reg reg_addr, std::int32_t offset)
{
if (need_sib(reg_addr))
do_push(rex(0, reg_src, {}, reg_addr), 0x89_ub, modrm(MOD_MEM32, reg_src, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(0, reg_src, {}, reg_addr), 0x89_ub, modrm(MOD_MEM32, reg_src, reg_addr), offset);
}
void instruction_builder::mov_write_16(reg reg_src, reg reg_addr, std::int32_t offset)
{
if (need_sib(reg_addr))
do_push(0x66_ub, rex(0, reg_src, {}, reg_addr), 0x89_ub, modrm(MOD_MEM32, reg_src, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(0x66_ub, rex(0, reg_src, {}, reg_addr), 0x89_ub, modrm(MOD_MEM32, reg_src, reg_addr), offset);
}
void instruction_builder::mov_write_8(reg reg_src, reg reg_addr, std::int32_t offset)
{
if (need_sib(reg_addr))
do_push(rex(0, reg_src, {}, reg_addr), 0x88_ub, modrm(MOD_MEM32, reg_src, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(0, reg_src, {}, reg_addr), 0x88_ub, modrm(MOD_MEM32, reg_src, reg_addr), offset);
}
void instruction_builder::mov_write_rip(reg reg_src, std::int32_t offset)
{
do_push(rex(1, reg_src, {}, {}), 0x89_ub, modrm(0, reg_src, 0b101), offset);
}
void instruction_builder::mov_write_rip_prev(reg reg_src, std::int32_t offset)
{
mov_write_rip(reg_src, offset - 7);
}
void instruction_builder::mov_read_xmm(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(0x66_ub, rex(1, reg_dst, {}, reg_addr), 0x0f_ub, 0x6e_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(0x66_ub, rex(1, reg_dst, {}, reg_addr), 0x0f_ub, 0x6e_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::mov_write_xmm(reg reg_src, reg reg_addr, std::int32_t offset)
{
if (need_sib(reg_addr))
do_push(0x66_ub, rex(0, reg_src, {}, reg_addr), 0x0f_ub, 0xd6_ub, modrm(MOD_MEM32, reg_src, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(0x66_ub, rex(0, reg_src, {}, reg_addr), 0x0f_ub, 0xd6_ub, modrm(MOD_MEM32, reg_src, reg_addr), offset);
}
void instruction_builder::mov_read_xmm_32(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_addr), 0x0f_ub, 0x10_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_addr), 0x0f_ub, 0x10_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::mov_write_xmm_32(reg reg_src, reg reg_addr, std::int32_t offset)
{
if (need_sib(reg_addr))
do_push(0xf3_ub, rex(0, reg_src, {}, reg_addr), 0x0f_ub, 0x11_ub, modrm(MOD_MEM32, reg_src, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(0xf3_ub, rex(0, reg_src, {}, reg_addr), 0x0f_ub, 0x11_ub, modrm(MOD_MEM32, reg_src, reg_addr), offset);
}
void instruction_builder::lea(reg reg_addr, std::int32_t offset, reg reg_dst)
{
if (need_sib(reg_addr))
do_push(rex(1, reg_dst, {}, reg_addr), 0x8d_ub, modrm(MOD_MEM32, reg_dst, reg_addr), sib(0, SIB_NOINDEX, reg_addr), offset);
else
do_push(rex(1, reg_dst, {}, reg_addr), 0x8d_ub, modrm(MOD_MEM32, reg_dst, reg_addr), offset);
}
void instruction_builder::lea_rip(std::int32_t offset, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, {}), 0x8d_ub, modrm(0, reg_dst, 0b101), offset);
}
void instruction_builder::lea_rip_prev(std::int32_t offset, reg reg_dst)
{
lea_rip(offset - 7, reg_dst);
}
void instruction_builder::push(reg reg)
{
do_push(rex(0, {}, {}, reg), opcode_add_reg(0x50, reg));
}
void instruction_builder::pop(reg reg)
{
do_push(rex(0, {}, {}, reg), opcode_add_reg(0x58, reg));
}
void instruction_builder::neg(reg reg)
{
do_push(rex(1, {}, {}, reg), 0xf7_ub, modrm(MOD_REG, 3, reg));
}
void instruction_builder::not_(reg reg)
{
do_push(rex(1, {}, {}, reg), 0xf7_ub, modrm(MOD_REG, 2, reg));
}
void instruction_builder::test(reg reg1, reg reg2)
{
do_push(rex(1, reg1, {}, reg2), 0x85_ub, modrm(MOD_REG, reg1, reg2));
}
void instruction_builder::add(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x03_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::sub(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x2b_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mul(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0xaf_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::udiv(reg reg_src)
{
do_push(rex(1, {}, {}, reg_src), 0xf7_ub, modrm(MOD_REG, 0b110, reg_src));
}
void instruction_builder::idiv(reg reg_src)
{
do_push(rex(1, {}, {}, reg_src), 0xf7_ub, modrm(MOD_REG, 0b111, reg_src));
}
void instruction_builder::cqo()
{
do_push(0x48_ub, 0x99_ub);
}
void instruction_builder::and_(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x23_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::or_(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0b_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xor_(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x33_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::shl(reg reg_dst)
{
do_push(rex(1, {}, {}, reg_dst), 0xd3_ub, modrm(MOD_REG, 0b100, reg_dst));
}
void instruction_builder::shr(reg reg_dst)
{
do_push(rex(1, {}, {}, reg_dst), 0xd3_ub, modrm(MOD_REG, 0b101, reg_dst));
}
void instruction_builder::sar(reg reg_dst)
{
do_push(rex(1, {}, {}, reg_dst), 0xd3_ub, modrm(MOD_REG, 0b111, reg_dst));
}
void instruction_builder::cmp(reg reg1, reg reg2)
{
do_push(rex(1, reg1, {}, reg2), 0x3b_ub, modrm(MOD_REG, reg1, reg2));
}
void instruction_builder::cmovz(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x44_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::cmovnz(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x45_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::cmovb(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x42_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::cmovnb(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x43_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::cmovl(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x4c_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::cmovnl(reg reg_src, reg reg_dst)
{
do_push(rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x4d_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::add_xmm(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x58_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::add_xmm_32(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x58_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::sub_xmm(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x5c_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::sub_xmm_32(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x5c_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mul_xmm(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x59_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::mul_xmm_32(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x59_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::div_xmm(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x5e_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::div_xmm_32(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x5e_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xor_xmm(reg reg_src, reg reg_dst)
{
do_push(0x66_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x57_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xor_xmm_32(reg reg_src, reg reg_dst)
{
do_push(rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x57_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::cmp_xmm(reg reg1, reg reg2)
{
do_push(0x66_ub, rex(0, reg1, {}, reg2), 0x0f_ub, 0x2e_ub, modrm(MOD_REG, reg1, reg2));
}
void instruction_builder::cmp_xmm_32(reg reg1, reg reg2)
{
do_push(rex(0, reg1, {}, reg2), 0x0f_ub, 0x2e_ub, modrm(MOD_REG, reg1, reg2));
}
void instruction_builder::gpr_to_xmm(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x2a_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::gpr_to_xmm_32(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x2a_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xmm_to_gpr(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x2d_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xmm_32_to_gpr(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(1, reg_dst, {}, reg_src), 0x0f_ub, 0x2d_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xmm_16_to_32(reg reg_src, reg reg_dst)
{
do_push(0xc4_ub, vex(reg_dst, {}, reg_src, 0b00010), 0b01111001_ub, 0x13_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xmm_32_to_16(reg reg_src, reg reg_dst)
{
do_push(0xc4_ub, vex(reg_dst, {}, reg_src, 0b00011), std::uint8_t(1 | ~(std::uint8_t(reg_src) << 3)), 0x1d_ub, modrm(MOD_REG, reg_dst, 0));
}
void instruction_builder::xmm_32_to_64(reg reg_src, reg reg_dst)
{
do_push(0xf3_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x5a_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::xmm_64_to_32(reg reg_src, reg reg_dst)
{
do_push(0xf2_ub, rex(0, reg_dst, {}, reg_src), 0x0f_ub, 0x5a_ub, modrm(MOD_REG, reg_dst, reg_src));
}
void instruction_builder::jump(std::int32_t offset)
{
do_push(0xe9_ub, offset);
}
void instruction_builder::jump_if_zero(std::int32_t offset)
{
do_push(0x0f_ub, 0x84_ub, offset);
}
void instruction_builder::jump_if_nonzero(std::int32_t offset)
{
do_push(0x0f_ub, 0x85_ub, offset);
}
void instruction_builder::jump_inject(std::uint8_t * opcode, std::int32_t offset)
{
auto src = (std::uint8_t const *)(&offset);
std::copy(src, src + 4, opcode + 1);
}
void instruction_builder::jump_inject_prev(std::uint8_t * opcode, std::int32_t offset)
{
jump_inject(opcode, offset - 5);
}
void instruction_builder::cjump_inject(std::uint8_t * opcode, std::int32_t offset)
{
auto src = (std::uint8_t const *)(&offset);
std::copy(src, src + 4, opcode + 2);
}
void instruction_builder::cjump_inject_prev(std::uint8_t * opcode, std::int32_t offset)
{
cjump_inject(opcode, offset - 6);
}
void instruction_builder::lea_rip_inject(std::uint8_t * opcode, std::int32_t offset)
{
auto src = (std::uint8_t const *)(&offset);
std::copy(src, src + 4, opcode + 3);
}
void instruction_builder::lea_rip_inject_prev(std::uint8_t * opcode, std::int32_t offset)
{
lea_rip_inject(opcode, offset - 7);
}
template <typename ... Args>
void instruction_builder::do_push(Args ... values)
{
push_bytes(code, values...);
}
}