use crate::mc_inst::{MCInst, MCOperand};
use crate::mc_streamer::x86_opcodes;
fn x86_64bit_reg(reg_id: u32) -> bool {
reg_id < 16
}
fn inst_is_64bit(inst: &MCInst) -> bool {
inst.size == 0 || inst.size >= 8
}
fn x86_reg_field(reg_id: u32) -> u8 {
if reg_id < 16 {
(reg_id % 8) as u8
} else if reg_id < 24 {
((reg_id - 16) % 8) as u8
} else {
(reg_id % 8) as u8
}
}
fn x86_reg_needs_rex_b(reg_id: u32) -> bool {
if reg_id < 16 {
reg_id >= 8
} else if reg_id < 24 {
(reg_id - 16) >= 8
} else {
reg_id >= 8
}
}
fn x86_reg_needs_rex_r(reg_id: u32) -> bool {
x86_reg_needs_rex_b(reg_id)
}
fn make_rex(w: bool, r: bool, x: bool, b: bool) -> u8 {
0x40 | ((w as u8) << 3) | ((r as u8) << 2) | ((x as u8) << 1) | (b as u8)
}
fn make_modrm(mod_field: u8, reg_opcode: u8, rm: u8) -> u8 {
((mod_field & 0x03) << 6) | ((reg_opcode & 0x07) << 3) | (rm & 0x07)
}
#[allow(dead_code)]
fn make_sib(scale: u8, index: u8, base: u8) -> u8 {
((scale & 0x03) << 6) | ((index & 0x07) << 3) | (base & 0x07)
}
fn push_i32_le(out: &mut Vec<u8>, val: i32) {
out.extend_from_slice(&val.to_le_bytes());
}
#[allow(dead_code)]
fn push_u32_le(out: &mut Vec<u8>, val: u32) {
out.extend_from_slice(&val.to_le_bytes());
}
fn push_i64_le(out: &mut Vec<u8>, val: i64) {
out.extend_from_slice(&val.to_le_bytes());
}
pub fn encode_x86_64(inst: &MCInst) -> Option<Vec<u8>> {
match inst.opcode {
x86_opcodes::NOP => encode_x86_nop(inst),
x86_opcodes::RET => encode_x86_ret(inst),
x86_opcodes::PUSH => encode_x86_push(inst),
x86_opcodes::POP => encode_x86_pop(inst),
x86_opcodes::MOV => encode_x86_mov(inst),
x86_opcodes::ADD => encode_x86_add(inst),
x86_opcodes::SUB => encode_x86_sub(inst),
x86_opcodes::MUL => encode_x86_mul(inst),
x86_opcodes::IMUL => encode_x86_imul(inst),
x86_opcodes::AND => encode_x86_and(inst),
x86_opcodes::OR => encode_x86_or(inst),
x86_opcodes::XOR => encode_x86_xor(inst),
x86_opcodes::CMP => encode_x86_cmp(inst),
x86_opcodes::JMP => encode_x86_jmp(inst),
x86_opcodes::CALL => encode_x86_call(inst),
x86_opcodes::JE => encode_x86_jcc(inst, 0x84),
x86_opcodes::JNE => encode_x86_jcc(inst, 0x85),
x86_opcodes::INC => encode_x86_inc(inst),
x86_opcodes::DEC => encode_x86_dec(inst),
x86_opcodes::LEA => encode_x86_lea(inst),
x86_opcodes::NOT => encode_x86_not(inst),
x86_opcodes::NEG => encode_x86_neg(inst),
x86_opcodes::SHL => encode_x86_shift(inst, 4),
x86_opcodes::SHR => encode_x86_shift(inst, 5),
x86_opcodes::SAR => encode_x86_shift(inst, 7),
x86_opcodes::DIV => encode_x86_div(inst),
x86_opcodes::IDIV => encode_x86_idiv(inst),
x86_opcodes::CDQ => encode_x86_cdq(inst),
x86_opcodes::CQO => encode_x86_cqo(inst),
x86_opcodes::MOVSX => encode_x86_movsx(inst),
x86_opcodes::MOVSXD => encode_x86_movsxd(inst),
x86_opcodes::MOVZX => encode_x86_movzx(inst),
x86_opcodes::SETO => encode_x86_setcc(inst, 0x90),
x86_opcodes::SETNO => encode_x86_setcc(inst, 0x91),
x86_opcodes::SETB => encode_x86_setcc(inst, 0x92),
x86_opcodes::SETAE => encode_x86_setcc(inst, 0x93),
x86_opcodes::SETE => encode_x86_setcc(inst, 0x94),
x86_opcodes::SETNE => encode_x86_setcc(inst, 0x95),
x86_opcodes::SETBE => encode_x86_setcc(inst, 0x96),
x86_opcodes::SETA => encode_x86_setcc(inst, 0x97),
x86_opcodes::SETS => encode_x86_setcc(inst, 0x98),
x86_opcodes::SETNS => encode_x86_setcc(inst, 0x99),
x86_opcodes::SETP => encode_x86_setcc(inst, 0x9A),
x86_opcodes::SETNP => encode_x86_setcc(inst, 0x9B),
x86_opcodes::SETL => encode_x86_setcc(inst, 0x9C),
x86_opcodes::SETGE => encode_x86_setcc(inst, 0x9D),
x86_opcodes::SETLE => encode_x86_setcc(inst, 0x9E),
x86_opcodes::SETG => encode_x86_setcc(inst, 0x9F),
x86_opcodes::CMOVE => encode_x86_cmovcc(inst, 0x44),
x86_opcodes::CMOVNE => encode_x86_cmovcc(inst, 0x45),
x86_opcodes::CMOVB => encode_x86_cmovcc(inst, 0x42),
x86_opcodes::CMOVAE => encode_x86_cmovcc(inst, 0x43),
x86_opcodes::CMOVBE => encode_x86_cmovcc(inst, 0x46),
x86_opcodes::CMOVA => encode_x86_cmovcc(inst, 0x47),
x86_opcodes::CMOVL => encode_x86_cmovcc(inst, 0x4C),
x86_opcodes::CMOVGE => encode_x86_cmovcc(inst, 0x4D),
x86_opcodes::CMOVLE => encode_x86_cmovcc(inst, 0x4E),
x86_opcodes::CMOVG => encode_x86_cmovcc(inst, 0x4F),
x86_opcodes::LOAD => encode_x86_load(inst),
x86_opcodes::STORE => encode_x86_store(inst),
x86_opcodes::ADDSS => encode_x86_sse_binary(inst, 0x58, 0xF3),
x86_opcodes::ADDSD => encode_x86_sse_binary(inst, 0x58, 0xF2),
x86_opcodes::SUBSS => encode_x86_sse_binary(inst, 0x5C, 0xF3),
x86_opcodes::SUBSD => encode_x86_sse_binary(inst, 0x5C, 0xF2),
x86_opcodes::MULSS => encode_x86_sse_binary(inst, 0x59, 0xF3),
x86_opcodes::MULSD => encode_x86_sse_binary(inst, 0x59, 0xF2),
x86_opcodes::DIVSS => encode_x86_sse_binary(inst, 0x5E, 0xF3),
x86_opcodes::DIVSD => encode_x86_sse_binary(inst, 0x5E, 0xF2),
x86_opcodes::UCOMISS => encode_x86_sse_binary(inst, 0x2E, 0x00),
x86_opcodes::UCOMISD => encode_x86_sse_binary(inst, 0x2E, 0x66),
x86_opcodes::MOVSS => encode_x86_sse_binary(inst, 0x10, 0xF3),
x86_opcodes::MOVSD => encode_x86_sse_binary(inst, 0x10, 0xF2),
x86_opcodes::XORPS => encode_x86_sse_binary(inst, 0x57, 0x00),
x86_opcodes::XORPD => encode_x86_sse_binary(inst, 0x57, 0x66),
x86_opcodes::CVTSI2SS => encode_x86_sse_cvt_i2f(inst, 0x2A, true),
x86_opcodes::CVTSI2SD => encode_x86_sse_cvt_i2f(inst, 0x2A, false),
x86_opcodes::CVTTSS2SI => encode_x86_sse_cvt_f2i(inst, 0x2C, true),
x86_opcodes::CVTTSD2SI => encode_x86_sse_cvt_f2i(inst, 0x2C, false),
x86_opcodes::MOVD => encode_x86_movd(inst, false, false),
x86_opcodes::MOVQ => encode_x86_movd(inst, true, false),
x86_opcodes::MOVD_FROM_XMM => encode_x86_movd(inst, false, true),
x86_opcodes::MOVQ_FROM_XMM => encode_x86_movd(inst, true, true),
x86_opcodes::MOVSS_LOAD => encode_x86_sse_mem(inst, 0x10, 0xF3, false),
x86_opcodes::MOVSD_LOAD => encode_x86_sse_mem(inst, 0x10, 0xF2, false),
x86_opcodes::MOVSS_STORE => encode_x86_sse_mem(inst, 0x11, 0xF3, true),
x86_opcodes::MOVSD_STORE => encode_x86_sse_mem(inst, 0x11, 0xF2, true),
_ => None,
}
}
fn encode_x86_nop(_inst: &MCInst) -> Option<Vec<u8>> {
Some(vec![0x90])
}
fn encode_x86_ret(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.is_empty() {
Some(vec![0xC3])
} else if let Some(MCOperand::Imm(imm)) = inst.operands.first() {
let mut out = Vec::with_capacity(3);
out.push(0xC2);
let imm16 = *imm as u16;
out.extend_from_slice(&imm16.to_le_bytes());
Some(out)
} else {
None
}
}
fn encode_x86_push(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
if let Some(reg) = inst.operands[0].get_reg() {
let mut out = Vec::with_capacity(2);
if reg >= 8 {
out.push(0x41); }
out.push(0x50 + (reg % 8) as u8);
Some(out)
} else {
None
}
}
fn encode_x86_pop(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
if let Some(reg) = inst.operands[0].get_reg() {
let mut out = Vec::with_capacity(2);
if reg >= 8 {
out.push(0x41); }
out.push(0x58 + (reg % 8) as u8);
Some(out)
} else {
None
}
}
fn encode_x86_mov(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst_is_reg = inst.operands[0].is_reg();
let src_is_reg = inst.operands[1].is_reg();
let src_is_imm = inst.operands[1].is_imm();
if dst_is_reg && src_is_reg {
let dst = inst.operands[0].get_reg().unwrap();
let src = inst.operands[1].get_reg().unwrap();
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let w = is64;
let rx_r = x86_reg_needs_rex_r(src);
let rx_b = x86_reg_needs_rex_b(dst);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(0x89);
out.push(make_modrm(0x03, x86_reg_field(src), x86_reg_field(dst)));
Some(out)
}
else if dst_is_reg && src_is_imm {
let dst = inst.operands[0].get_reg().unwrap();
let imm = inst.operands[1].get_imm().unwrap();
let is64 = inst_is_64bit(inst);
if is64 {
let mut out = Vec::with_capacity(10);
let rex = make_rex(true, false, false, x86_reg_needs_rex_b(dst));
out.push(rex);
out.push(0xB8 + x86_reg_field(dst));
push_i64_le(&mut out, imm);
Some(out)
} else {
let mut out = Vec::with_capacity(6);
if x86_reg_needs_rex_b(dst) {
out.push(0x41); }
out.push(0xB8 + x86_reg_field(dst));
push_i32_le(&mut out, imm as i32);
Some(out)
}
}
else {
None
}
}
fn encode_x86_load(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let is64 = inst_is_64bit(inst);
let is_byte = inst.size == 1;
let mut out = Vec::with_capacity(4);
if is_byte {
let rx_r = x86_reg_needs_rex_r(dst);
let rx_b = x86_reg_needs_rex_b(src);
if rx_r || rx_b {
out.push(make_rex(false, rx_r, false, rx_b));
}
out.extend_from_slice(&[0x0F, 0xB6]);
let rm_field = x86_reg_field(src);
out.push(make_modrm(0x00, x86_reg_field(dst), rm_field));
if rm_field == 4 {
out.push(0x24);
}
return Some(out);
}
let w = is64;
let rx_r = x86_reg_needs_rex_r(dst);
let rx_b = x86_reg_needs_rex_b(src);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(0x8B);
let rm_field = x86_reg_field(src);
out.push(make_modrm(0x00, x86_reg_field(dst), rm_field));
if rm_field == 4 {
out.push(0x24); }
Some(out)
}
fn encode_x86_store(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let ptr = inst.operands[0].get_reg()?;
let val = inst.operands[1].get_reg()?;
let is64 = inst_is_64bit(inst);
let is_byte = inst.size == 1;
let mut out = Vec::with_capacity(3);
if is_byte {
let val_needs_rex_present = val >= 4; let rx_r = val >= 8; let rx_b = x86_reg_needs_rex_b(ptr); let need_rex = val_needs_rex_present || rx_b;
if need_rex {
out.push(make_rex(false, rx_r, false, rx_b));
}
out.push(0x88);
let rm_field = x86_reg_field(ptr);
out.push(make_modrm(0x00, x86_reg_field(val), rm_field));
if rm_field == 4 {
out.push(0x24);
}
return Some(out);
}
let w = is64;
let rx_r = x86_reg_needs_rex_r(val);
let rx_b = x86_reg_needs_rex_b(ptr);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(0x89);
let rm_field = x86_reg_field(ptr);
out.push(make_modrm(0x00, x86_reg_field(val), rm_field));
if rm_field == 4 {
out.push(0x24);
}
Some(out)
}
fn encode_x86_add(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm();
let src = inst.operands[1].get_reg();
let is64 = inst_is_64bit(inst);
if let Some(src_reg) = src {
let mut out = Vec::with_capacity(3);
let w = is64;
let rx_r = x86_reg_needs_rex_r(dst);
let rx_b = x86_reg_needs_rex_b(src_reg);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(0x01); out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src_reg)));
Some(out)
} else if let Some(imm_val) = imm {
encode_alu_imm(x86_reg_field(dst), dst, imm_val, 0x81, 0x83, 0, is64)
} else {
None
}
}
fn encode_x86_sub(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm();
let src = inst.operands[1].get_reg();
let is64 = inst_is_64bit(inst);
if let Some(src_reg) = src {
let mut out = Vec::with_capacity(3);
let w = is64;
let rx_r = x86_reg_needs_rex_r(dst);
let rx_b = x86_reg_needs_rex_b(src_reg);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(0x29); out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src_reg)));
Some(out)
} else if let Some(imm_val) = imm {
encode_alu_imm(x86_reg_field(dst), dst, imm_val, 0x81, 0x83, 5, is64)
} else {
None
}
}
fn encode_x86_imul(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(4);
let need_rex = is64 || x86_reg_needs_rex_r(dst) || x86_reg_needs_rex_b(src);
if need_rex {
out.push(make_rex(
is64,
x86_reg_needs_rex_r(dst),
false,
x86_reg_needs_rex_b(src),
));
}
out.push(0x0F);
out.push(0xAF);
out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src)));
Some(out)
}
fn encode_x86_mul(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xF7);
out.push(make_modrm(0x03, 4, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_and(inst: &MCInst) -> Option<Vec<u8>> {
encode_binary_reg_imm(inst, 0x21, 4)
}
fn encode_x86_or(inst: &MCInst) -> Option<Vec<u8>> {
encode_binary_reg_imm(inst, 0x09, 1)
}
fn encode_x86_xor(inst: &MCInst) -> Option<Vec<u8>> {
encode_binary_reg_imm(inst, 0x31, 6)
}
fn encode_x86_cmp(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let lhs = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm();
let rhs = inst.operands[1].get_reg();
if let Some(rhs_reg) = rhs {
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let w = is64;
let rx_r = x86_reg_needs_rex_r(rhs_reg);
let rx_b = x86_reg_needs_rex_b(lhs);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(0x39); out.push(make_modrm(0x03, x86_reg_field(rhs_reg), x86_reg_field(lhs)));
Some(out)
} else if let Some(imm_val) = imm {
encode_alu_imm(
x86_reg_field(lhs),
lhs,
imm_val,
0x81,
0x83,
7,
inst_is_64bit(inst),
)
} else {
None
}
}
fn encode_x86_jmp(inst: &MCInst) -> Option<Vec<u8>> {
let mut out = Vec::with_capacity(5);
out.push(0xE9);
if let Some(MCOperand::Imm(offset)) = inst.operands.first() {
push_i32_le(&mut out, *offset as i32);
} else {
push_i32_le(&mut out, 0);
}
Some(out)
}
fn encode_x86_call(inst: &MCInst) -> Option<Vec<u8>> {
match inst.operands.first() {
Some(MCOperand::Imm(offset)) => {
let mut out = Vec::with_capacity(5);
out.push(0xE8);
push_i32_le(&mut out, *offset as i32);
Some(out)
}
Some(MCOperand::Reg(reg)) => {
let rm = *reg & 7;
let modrm = (0xD0u32 | rm) as u8;
let mut out = Vec::with_capacity(3);
if *reg >= 8 {
out.push(0x41); }
out.push(0xFF);
out.push(modrm);
Some(out)
}
_ => {
let mut out = Vec::with_capacity(5);
out.push(0xE8);
push_i32_le(&mut out, 0);
Some(out)
}
}
}
fn encode_x86_jcc(inst: &MCInst, cond_byte: u8) -> Option<Vec<u8>> {
let mut out = Vec::with_capacity(6);
out.push(0x0F);
out.push(cond_byte);
if let Some(MCOperand::Imm(offset)) = inst.operands.first() {
push_i32_le(&mut out, *offset as i32);
} else {
push_i32_le(&mut out, 0);
}
Some(out)
}
fn encode_x86_inc(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xFF);
out.push(make_modrm(0x03, 0, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_dec(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xFF);
out.push(make_modrm(0x03, 1, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_lea(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
if inst.operands[1].is_reg() {
eprintln!(
"LEA_REG: ops[0]={:?} ops[1]={:?}",
inst.operands[0], inst.operands[1]
);
}
if let Some(base_reg) = inst.operands[1].get_reg() {
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_r(dst) || x86_reg_needs_rex_b(base_reg);
if need_rex {
out.push(make_rex(
is64,
x86_reg_needs_rex_r(dst),
false,
x86_reg_needs_rex_b(base_reg),
));
}
out.push(0x8D);
out.push(make_modrm(
0x00,
x86_reg_field(dst),
x86_reg_field(base_reg),
));
Some(out)
} else if inst.operands[1].is_expr() {
let mut out = Vec::with_capacity(7);
let need_rex = is64 || x86_reg_needs_rex_r(dst);
if need_rex {
out.push(make_rex(is64, x86_reg_needs_rex_r(dst), false, false));
}
out.push(0x8D);
out.push(make_modrm(0x00, x86_reg_field(dst), 5));
out.extend_from_slice(&[0u8; 4]);
Some(out)
} else {
None
}
}
fn encode_x86_not(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xF7);
out.push(make_modrm(0x03, 2, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_neg(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xF7);
out.push(make_modrm(0x03, 3, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_cmovcc(inst: &MCInst, cc_byte: u8) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(4);
let need_rex = is64 || x86_reg_needs_rex_r(src) || x86_reg_needs_rex_b(dst);
if need_rex {
out.push(make_rex(
is64,
x86_reg_needs_rex_r(src),
false,
x86_reg_needs_rex_b(dst),
));
}
out.push(0x0F);
out.push(cc_byte);
out.push(make_modrm(0x03, x86_reg_field(src), x86_reg_field(dst)));
Some(out)
}
fn encode_x86_shift(inst: &MCInst, reg_opcode_field: u8) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let is_cl = inst.operands[1].get_reg() == Some(1);
let mut out = Vec::with_capacity(4);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
if is_cl {
out.push(0xD3);
out.push(make_modrm(0x03, reg_opcode_field, x86_reg_field(reg)));
} else if let Some(imm_val) = inst.operands[1].get_imm() {
if imm_val == 1 {
out.push(0xD1);
} else {
out.push(0xC1);
}
out.push(make_modrm(0x03, reg_opcode_field, x86_reg_field(reg)));
if imm_val != 1 {
out.push(imm_val as u8);
}
} else {
return None;
}
Some(out)
}
fn encode_x86_div(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xF7);
out.push(make_modrm(0x03, 6, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_idiv(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let reg = inst.operands[0].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let need_rex = is64 || x86_reg_needs_rex_b(reg);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(reg)));
}
out.push(0xF7);
out.push(make_modrm(0x03, 7, x86_reg_field(reg)));
Some(out)
}
fn encode_x86_cdq(_inst: &MCInst) -> Option<Vec<u8>> {
Some(vec![0x99])
}
fn encode_x86_cqo(_inst: &MCInst) -> Option<Vec<u8>> {
Some(vec![0x48, 0x99])
}
fn encode_alu_imm(
rm_field: u8,
rm_reg_id: u32,
imm: i64,
op_imm32: u8,
op_imm8: u8,
reg_opcode_field: u8,
is64: bool,
) -> Option<Vec<u8>> {
if (-128..=127).contains(&imm) {
let mut out = Vec::with_capacity(4);
let need_rex = is64 || x86_reg_needs_rex_b(rm_reg_id);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(rm_reg_id)));
}
out.push(op_imm8);
out.push(make_modrm(0x03, reg_opcode_field, rm_field));
out.push(imm as u8);
Some(out)
} else {
let mut out = Vec::with_capacity(7);
let need_rex = is64 || x86_reg_needs_rex_b(rm_reg_id);
if need_rex {
out.push(make_rex(is64, false, false, x86_reg_needs_rex_b(rm_reg_id)));
}
out.push(op_imm32);
out.push(make_modrm(0x03, reg_opcode_field, rm_field));
push_i32_le(&mut out, imm as i32);
Some(out)
}
}
fn encode_binary_reg_imm(inst: &MCInst, op_reg_reg: u8, reg_opcode_field: u8) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm();
let src = inst.operands[1].get_reg();
if let Some(src_reg) = src {
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(3);
let w = is64;
let rx_r = x86_reg_needs_rex_r(dst);
let rx_b = x86_reg_needs_rex_b(src_reg);
let need_rex = w || rx_r || rx_b;
if need_rex {
let rex = make_rex(w, rx_r, false, rx_b);
out.push(rex);
}
out.push(op_reg_reg);
out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src_reg)));
Some(out)
} else if let Some(imm_val) = imm {
encode_alu_imm(
x86_reg_field(dst),
dst,
imm_val,
0x81,
0x83,
reg_opcode_field,
inst_is_64bit(inst),
)
} else {
None
}
}
fn encode_x86_movsxd(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let mut out = Vec::with_capacity(3);
let rex = make_rex(
true, x86_reg_needs_rex_r(dst),
false,
x86_reg_needs_rex_b(src),
);
out.push(rex);
out.push(0x63);
out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src)));
Some(out)
}
fn encode_x86_movsx(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let is64 = inst_is_64bit(inst);
let mut out = Vec::with_capacity(4);
let src_needs_rex_low = src >= 4 && src < 8; let rex_r = x86_reg_needs_rex_r(dst);
let rex_b = x86_reg_needs_rex_b(src);
let need_rex = is64 || src_needs_rex_low || rex_r || rex_b;
if need_rex {
out.push(make_rex(is64, rex_r, false, rex_b));
}
out.extend_from_slice(&[0x0F, 0xBE]);
out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src)));
Some(out)
}
fn encode_x86_movzx(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let mut out = Vec::with_capacity(4);
let rex_r = x86_reg_needs_rex_r(dst);
let rex_b = x86_reg_needs_rex_b(src);
let needs_rex_for_low_byte = (src >= 4 && src < 8) || (dst >= 4 && dst < 8);
let needs_rex = rex_r || rex_b || needs_rex_for_low_byte;
if needs_rex {
out.push(make_rex(false, rex_r, false, rex_b));
}
out.extend_from_slice(&[0x0F, 0xB6]);
out.push(make_modrm(0x03, x86_reg_field(dst), x86_reg_field(src)));
Some(out)
}
fn encode_x86_setcc(inst: &MCInst, opcode2: u8) -> Option<Vec<u8>> {
if inst.operands.len() != 1 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let mut out = Vec::with_capacity(3);
if x86_reg_needs_rex_b(dst) {
out.push(0x41); } else if dst >= 4 && dst < 8 {
out.push(0x40); }
out.extend_from_slice(&[0x0F, opcode2]);
out.push(make_modrm(0x03, 0, x86_reg_field(dst)));
Some(out)
}
fn encode_x86_sse_binary(inst: &MCInst, opcode2: u8, prefix: u8) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let src = inst.operands[0].get_reg()?;
let dst = inst.operands[1].get_reg()?;
let mut out = Vec::with_capacity(4);
if prefix != 0x00 {
out.push(prefix);
}
let src_idx = src.wrapping_sub(64);
let dst_idx = dst.wrapping_sub(64);
let need_rex_r = dst_idx >= 8;
let need_rex_b = src_idx >= 8;
if need_rex_r || need_rex_b {
out.push(make_rex(false, need_rex_r, false, need_rex_b));
}
out.push(0x0F);
out.push(opcode2);
let reg_field = (dst_idx & 0x07) as u8;
let rm_field = (src_idx & 0x07) as u8;
out.push(make_modrm(0x03, reg_field, rm_field));
Some(out)
}
fn encode_x86_sse_cvt_i2f(inst: &MCInst, opcode2: u8, is_single: bool) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let xmm_dst = inst.operands[0].get_reg()?;
let int_src = inst.operands[1].get_reg()?;
let mut out = Vec::with_capacity(5);
out.push(if is_single { 0xF3 } else { 0xF2 });
let need_w = true; let need_rex_r = x86_reg_needs_rex_r(int_src);
let dst_idx = xmm_dst.wrapping_sub(64);
let need_rex_b = dst_idx >= 8;
out.push(make_rex(need_w, need_rex_r, false, need_rex_b));
out.push(0x0F);
out.push(opcode2);
let reg_field = x86_reg_field(int_src);
let rm_field = (dst_idx & 0x07) as u8;
out.push(make_modrm(0x03, reg_field, rm_field));
Some(out)
}
fn encode_x86_sse_cvt_f2i(inst: &MCInst, opcode2: u8, is_single: bool) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let int_dst = inst.operands[0].get_reg()?;
let xmm_src = inst.operands[1].get_reg()?;
let mut out = Vec::with_capacity(5);
out.push(if is_single { 0xF3 } else { 0xF2 });
let need_w = true; let src_idx = xmm_src.wrapping_sub(64);
let need_rex_r = src_idx >= 8;
let need_rex_b = x86_reg_needs_rex_b(int_dst);
out.push(make_rex(need_w, need_rex_r, false, need_rex_b));
out.push(0x0F);
out.push(opcode2);
let reg_field = (src_idx & 0x07) as u8;
let rm_field = x86_reg_field(int_dst);
out.push(make_modrm(0x03, reg_field, rm_field));
Some(out)
}
fn encode_x86_movd(inst: &MCInst, is_64bit: bool, from_xmm: bool) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let mut out = Vec::with_capacity(4);
out.push(0x66);
if from_xmm {
let xmm_src = inst.operands[0].get_reg()?;
let gpr_dst = inst.operands[1].get_reg()?;
let xmm_idx = xmm_src.wrapping_sub(64);
let need_w = is_64bit;
let need_rex_r = xmm_idx >= 8;
let need_rex_b = x86_reg_needs_rex_b(gpr_dst);
if need_w || need_rex_r || need_rex_b {
out.push(make_rex(need_w, need_rex_r, false, need_rex_b));
}
out.extend_from_slice(&[0x0F, 0x7E]);
out.push(make_modrm(
0x03,
(xmm_idx & 0x07) as u8,
x86_reg_field(gpr_dst),
));
} else {
let gpr_reg = inst.operands[0].get_reg()?;
let xmm_reg = inst.operands[1].get_reg()?;
let xmm_idx = xmm_reg.wrapping_sub(64);
let need_w = is_64bit;
let need_rex_r = xmm_idx >= 8;
let need_rex_b = x86_reg_needs_rex_b(gpr_reg);
if need_w || need_rex_r || need_rex_b {
out.push(make_rex(need_w, need_rex_r, false, need_rex_b));
}
out.extend_from_slice(&[0x0F, 0x6E]);
out.push(make_modrm(
0x03,
(xmm_idx & 0x07) as u8, x86_reg_field(gpr_reg), ));
}
Some(out)
}
fn encode_x86_sse_mem(inst: &MCInst, opcode2: u8, prefix: u8, is_store: bool) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let xmm_reg = inst.operands[0].get_reg()?;
let ptr_reg = inst.operands[1].get_reg()?;
let xmm_idx = xmm_reg.wrapping_sub(64);
let mut out = Vec::with_capacity(4);
out.push(prefix); let need_rex_r = xmm_idx >= 8;
let need_rex_b = x86_reg_needs_rex_b(ptr_reg);
if need_rex_r || need_rex_b {
out.push(make_rex(false, need_rex_r, false, need_rex_b));
}
out.extend_from_slice(&[0x0F, opcode2]);
out.push(make_modrm(
0x00,
(xmm_idx & 0x07) as u8,
x86_reg_field(ptr_reg),
));
Some(out)
}
pub fn encode_aarch64(inst: &MCInst) -> Option<Vec<u8>> {
match inst.opcode {
1 => encode_aarch64_mov(inst), 2 => encode_aarch64_add(inst), 3 => encode_aarch64_sub(inst), 4 => encode_aarch64_mul(inst), 5 => encode_aarch64_and(inst), 6 => encode_aarch64_orr(inst), 7 => encode_aarch64_eor(inst), 0 => Some(encode_aarch64_nop()), 17 => Some(encode_aarch64_ret()), 15 => encode_aarch64_b(inst), 16 => encode_aarch64_bl(inst), _ => None,
}
}
fn encode_aarch64_nop() -> Vec<u8> {
0xD503201Fu32.to_le_bytes().to_vec() }
fn encode_aarch64_ret() -> Vec<u8> {
0xD65F03C0u32.to_le_bytes().to_vec() }
fn encode_aarch64_mov(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm().unwrap_or(0);
let mut insn: u32 = 0xD2800000; insn |= dst & 0x1F;
insn |= ((imm as u32) & 0xFFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_add(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let imm = inst.operands[2].get_imm().unwrap_or(0);
let mut insn: u32 = 0x91000000; insn |= dst & 0x1F;
insn |= (src & 0x1F) << 5;
insn |= ((imm as u32) & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_sub(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let imm = inst.operands[2].get_imm().unwrap_or(0);
let mut insn: u32 = 0xD1000000; insn |= dst & 0x1F;
insn |= (src & 0x1F) << 5;
insn |= ((imm as u32) & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_mul(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src1 = inst.operands[1].get_reg()?;
let src2 = inst.operands[2].get_reg()?;
let mut insn: u32 = 0x9B007C00; insn |= dst & 0x1F;
insn |= (src1 & 0x1F) << 5;
insn |= (src2 & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_and(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src1 = inst.operands[1].get_reg()?;
let src2 = inst.operands[2].get_reg()?;
let mut insn: u32 = 0x8A000000; insn |= dst & 0x1F;
insn |= (src1 & 0x1F) << 5;
insn |= (src2 & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_orr(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src1 = inst.operands[1].get_reg()?;
let src2 = inst.operands[2].get_reg()?;
let mut insn: u32 = 0xAA000000; insn |= dst & 0x1F;
insn |= (src1 & 0x1F) << 5;
insn |= (src2 & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_eor(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src1 = inst.operands[1].get_reg()?;
let src2 = inst.operands[2].get_reg()?;
let mut insn: u32 = 0xCA000000; insn |= dst & 0x1F;
insn |= (src1 & 0x1F) << 5;
insn |= (src2 & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_b(inst: &MCInst) -> Option<Vec<u8>> {
let offset = inst.operands.first().and_then(|o| o.get_imm()).unwrap_or(0);
let imm26 = (offset as u32) & 0x03FFFFFF;
let insn: u32 = 0x14000000 | imm26;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_bl(inst: &MCInst) -> Option<Vec<u8>> {
let offset = inst.operands.first().and_then(|o| o.get_imm()).unwrap_or(0);
let imm26 = (offset as u32) & 0x03FFFFFF;
let insn: u32 = 0x94000000 | imm26;
Some(insn.to_le_bytes().to_vec())
}
pub fn encode_arm32(inst: &MCInst) -> Option<Vec<u8>> {
match inst.opcode {
0 => encode_arm32_nop(inst), 1 => encode_arm32_mov(inst), 2 => encode_arm32_movw(inst), 3 => encode_arm32_movt(inst), 4 => encode_arm32_add(inst), 5 => encode_arm32_sub(inst), 6 => encode_arm32_mul(inst), 7 => encode_arm32_and(inst), 8 => encode_arm32_orr(inst), 9 => encode_arm32_eor(inst), _ => None,
}
}
fn encode_arm32_nop(_inst: &MCInst) -> Option<Vec<u8>> {
Some(0xE320F000u32.to_le_bytes().to_vec())
}
fn encode_arm32_mov(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src = inst.operands[1].get_reg()?;
let mut insn: u32 = 0xE1A00000;
insn |= (dst & 0xF) << 12;
insn |= src & 0xF;
Some(insn.to_le_bytes().to_vec())
}
fn encode_arm32_movw(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0xE3000000; insn |= (dst & 0xF) << 12;
insn |= ((imm >> 12) & 0xF) << 16; insn |= imm & 0xFFF; Some(insn.to_le_bytes().to_vec())
}
fn encode_arm32_movt(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let imm = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0xE3400000; insn |= (dst & 0xF) << 12;
insn |= ((imm >> 12) & 0xF) << 16;
insn |= imm & 0xFFF;
Some(insn.to_le_bytes().to_vec())
}
fn encode_arm32_add(inst: &MCInst) -> Option<Vec<u8>> {
encode_arm32_alu_reg(inst, 0xE0800000)
}
fn encode_arm32_sub(inst: &MCInst) -> Option<Vec<u8>> {
encode_arm32_alu_reg(inst, 0xE0400000)
}
fn encode_arm32_mul(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src1 = inst.operands[1].get_reg()?;
let src2 = inst.operands[2].get_reg()?;
let mut insn: u32 = 0xE0000090; insn |= (dst & 0xF) << 16;
insn |= (src1 & 0xF) << 8;
insn |= src2 & 0xF;
Some(insn.to_le_bytes().to_vec())
}
fn encode_arm32_and(inst: &MCInst) -> Option<Vec<u8>> {
encode_arm32_alu_reg(inst, 0xE0000000)
}
fn encode_arm32_orr(inst: &MCInst) -> Option<Vec<u8>> {
encode_arm32_alu_reg(inst, 0xE1800000)
}
fn encode_arm32_eor(inst: &MCInst) -> Option<Vec<u8>> {
encode_arm32_alu_reg(inst, 0xE0200000)
}
fn encode_arm32_alu_reg(inst: &MCInst, base_insn: u32) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let dst = inst.operands[0].get_reg()?;
let src1 = inst.operands[1].get_reg()?;
let src2 = inst.operands[2].get_reg()?;
let mut insn = base_insn;
insn |= (dst & 0xF) << 12;
insn |= (src1 & 0xF) << 16;
insn |= src2 & 0xF;
Some(insn.to_le_bytes().to_vec())
}
#[derive(Debug, Clone)]
pub struct MCFixup {
pub offset: usize,
pub kind: FixupKind,
pub symbol: Option<String>,
pub value: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FixupKind {
Rel32,
Rel8,
Abs64,
Abs32,
}
#[derive(Debug, Clone)]
pub struct MCFragment {
pub data: Vec<u8>,
pub is_instruction: bool,
pub fixups: Vec<MCFixup>,
pub alignment: u8,
}
impl MCFragment {
pub fn new_instruction(data: Vec<u8>) -> Self {
Self {
data,
is_instruction: true,
fixups: Vec::new(),
alignment: 1,
}
}
pub fn new_data(data: Vec<u8>) -> Self {
Self {
data,
is_instruction: false,
fixups: Vec::new(),
alignment: 1,
}
}
pub fn add_fixup(&mut self, fixup: MCFixup) {
self.fixups.push(fixup);
}
}
#[derive(Debug, Clone)]
pub struct MCSection {
pub name: String,
pub fragments: Vec<MCFragment>,
pub section_type: SectionType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionType {
Text,
Data,
Rodata,
Bss,
}
impl MCSection {
pub fn new(name: &str, sec_type: SectionType) -> Self {
Self {
name: name.to_string(),
fragments: Vec::new(),
section_type: sec_type,
}
}
pub fn add_fragment(&mut self, frag: MCFragment) {
self.fragments.push(frag);
}
}
pub struct MCAssembler {
pub sections: Vec<MCSection>,
pub target_triple: String,
pub symbols: Vec<(String, usize, usize, usize)>,
}
impl MCAssembler {
pub fn new(triple: &str) -> Self {
Self {
sections: Vec::new(),
target_triple: triple.to_string(),
symbols: Vec::new(),
}
}
pub fn get_or_create_section(&mut self, name: &str, sec_type: SectionType) -> usize {
if let Some(idx) = self.sections.iter().position(|s| s.name == name) {
return idx;
}
self.sections.push(MCSection::new(name, sec_type));
self.sections.len() - 1
}
pub fn emit_instruction(&mut self, bytes: Vec<u8>) {
let sec_idx = self.get_or_create_section(".text", SectionType::Text);
self.sections[sec_idx].add_fragment(MCFragment::new_instruction(bytes));
}
pub fn emit_data(&mut self, bytes: Vec<u8>, section: &str) {
let sec_idx = self.get_or_create_section(section, SectionType::Data);
self.sections[sec_idx].add_fragment(MCFragment::new_data(bytes));
}
pub fn define_symbol(&mut self, name: &str, sec_idx: usize, frag_idx: usize, offset: usize) {
self.symbols
.push((name.to_string(), sec_idx, frag_idx, offset));
}
pub fn section_size(&self, sec_idx: usize) -> usize {
self.sections[sec_idx]
.fragments
.iter()
.map(|f| f.data.len())
.sum()
}
pub fn flatten_section(&self, sec_idx: usize) -> Vec<u8> {
let mut out = Vec::new();
for frag in &self.sections[sec_idx].fragments {
out.extend_from_slice(&frag.data);
}
out
}
pub fn flatten_all(&self) -> (Vec<u8>, Vec<(String, usize, usize)>) {
let mut out = Vec::new();
let mut offsets = Vec::new();
for sec in &self.sections {
let start = out.len();
for frag in &sec.fragments {
out.extend_from_slice(&frag.data);
}
let end = out.len();
offsets.push((sec.name.clone(), start, end - start));
}
(out, offsets)
}
}
impl Default for MCAssembler {
fn default() -> Self {
Self::new("x86_64-unknown-linux-gnu")
}
}
fn encode_a64_reg(reg: u32) -> u32 {
reg & 0x1F
}
fn encode_a64_imm_signed(value: i64, bits: u32) -> Option<u32> {
let min = -(1i64 << (bits - 1));
let max = (1i64 << (bits - 1)) - 1;
if value < min || value > max {
return None;
}
let mask = (1u64 << bits) - 1;
Some((value as u64 & mask) as u32)
}
fn encode_a64_imm_unsigned(value: u64, bits: u32) -> Option<u32> {
let max = (1u64 << bits) - 1;
if value > max {
return None;
}
Some(value as u32)
}
fn encode_a64_logical_imm(value: u64, size: u32) -> Option<(u32, u32, u32)> {
if value == 0 {
return Some((0, 0, 0));
}
if value == u64::MAX {
if size == 64 {
return Some((1, 0, 63));
} else {
return Some((0, 0, 31));
}
}
let effective_value = if size == 32 {
value & 0xFFFFFFFF
} else {
value
};
let trailing_ones = effective_value.trailing_zeros();
let total_ones = effective_value.count_ones();
if total_ones == 0 {
return Some((0, 0, 0));
}
let rotated = if trailing_ones > 0 {
(effective_value >> trailing_ones) | (effective_value << (64 - trailing_ones))
} else {
effective_value
};
let ones_end = match size {
32 => 32u32.saturating_sub(rotated.trailing_zeros()),
_ => 64u32.saturating_sub(rotated.trailing_zeros()),
};
let immr = trailing_ones as u32;
let imms = (ones_end - 1) as u32;
let n = if size == 64 { 1 } else { 0 };
Some((n, immr, imms))
}
fn encode_a64_addsub_imm(value: u64) -> Option<(u32, u32)> {
if value <= 0xFFF {
return Some((0, value as u32)); }
if value & 0xFFF == 0 && (value >> 12) <= 0xFFF {
return Some((1, (value >> 12) as u32)); }
None
}
fn encode_aarch64_ldr(inst: &MCInst, size: u32) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = match size {
0 => 0xB9400000, 1 => 0xF9400000, 2 => 0x3D400000, _ => 0xF9400000,
};
insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
let scaled_offset = match size {
0 => (offset / 4) & 0xFFF,
2 => (offset / 16) & 0xFFF,
_ => (offset / 8) & 0xFFF,
};
insn |= scaled_offset << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_str(inst: &MCInst, size: u32) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = match size {
0 => 0xB9000000, 1 => 0xF9000000, 2 => 0x3D000000, _ => 0xF9000000,
};
insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
let scaled_offset = match size {
0 => (offset / 4) & 0xFFF,
2 => (offset / 16) & 0xFFF,
_ => (offset / 8) & 0xFFF,
};
insn |= scaled_offset << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_ldp(inst: &MCInst, size: u32) -> Option<Vec<u8>> {
if inst.operands.len() < 4 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rt2 = encode_a64_reg(inst.operands[1].get_reg()?);
let rn = encode_a64_reg(inst.operands[2].get_reg()?);
let offset = inst.operands[3].get_imm().unwrap_or(0) as i32;
let mut insn: u32 = match size {
0 => 0x29400000, 1 => 0xA9400000, 2 => 0x2D400000, 3 => 0x6D400000, _ => 0xA9400000,
};
insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rt2 & 0x1F) << 10;
let scaled_offset = match size {
0 => (offset / 4) as u32 & 0x7F,
2 => (offset / 4) as u32 & 0x7F,
3 => (offset / 8) as u32 & 0x7F,
_ => (offset / 8) as u32 & 0x7F,
};
insn |= scaled_offset << 15;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_stp(inst: &MCInst, size: u32) -> Option<Vec<u8>> {
if inst.operands.len() < 4 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rt2 = encode_a64_reg(inst.operands[1].get_reg()?);
let rn = encode_a64_reg(inst.operands[2].get_reg()?);
let offset = inst.operands[3].get_imm().unwrap_or(0) as i32;
let mut insn: u32 = match size {
0 => 0x29000000, 1 => 0xA9000000, 2 => 0x2D000000, 3 => 0x6D000000, _ => 0xA9000000,
};
insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rt2 & 0x1F) << 10;
let scaled_offset = match size {
0 => (offset / 4) as u32 & 0x7F,
2 => (offset / 4) as u32 & 0x7F,
3 => (offset / 8) as u32 & 0x7F,
_ => (offset / 8) as u32 & 0x7F,
};
insn |= scaled_offset << 15;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_ldrb(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x39400000; insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (offset & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_strb(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x39000000; insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (offset & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_ldrh(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x79400000; insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= ((offset / 2) & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_strh(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x79000000; insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= ((offset / 2) & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_ldrsw(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0xB9800000;
insn |= rt & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= ((offset / 4) & 0xFFF) << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_ldr_literal(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let offset = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x58000000; insn |= rt & 0x1F;
insn |= (offset & 0x7FFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_cmp(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rn = encode_a64_reg(inst.operands[0].get_reg()?);
let op2 = &inst.operands[1];
if let Some(rm) = op2.get_reg() {
let rm_enc = encode_a64_reg(rm);
let mut insn: u32 = 0xEB00001F; insn |= (rn & 0x1F) << 5;
insn |= (rm_enc & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
} else if let Some(imm) = op2.get_imm() {
let imm_val = imm as u32;
let mut insn: u32 = 0xF100001F; insn |= (rn & 0x1F) << 5;
if let Some((shift, encoded)) = encode_a64_addsub_imm(imm_val as u64) {
insn |= (shift & 0x1) << 22;
insn |= (encoded & 0xFFF) << 10;
return Some(insn.to_le_bytes().to_vec());
}
None
} else {
None
}
}
fn encode_aarch64_tst(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rn = encode_a64_reg(inst.operands[0].get_reg()?);
if let Some(rm) = inst.operands[1].get_reg() {
let rm_enc = encode_a64_reg(rm);
let mut insn: u32 = 0xEA00001F; insn |= (rn & 0x1F) << 5;
insn |= (rm_enc & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
} else if let Some(imm) = inst.operands[1].get_imm() {
if let Some((n, immr, imms)) = encode_a64_logical_imm(imm as u64, 64) {
let mut insn: u32 = 0xF240001F; insn |= (rn & 0x1F) << 5;
insn |= (n & 0x1) << 22;
insn |= (immr & 0x3F) << 16;
insn |= (imms & 0x3F) << 10;
Some(insn.to_le_bytes().to_vec())
} else {
None
}
} else {
None
}
}
fn encode_aarch64_lsl(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let shift = inst.operands[2].get_imm().unwrap_or(0) as u32;
if shift > 63 {
return None;
}
let imms: u32 = 63;
let immr: u32 = ((64 - shift) % 64) & 0x3F;
let mut insn: u32 = 0xD3400000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (immr & 0x3F) << 16;
insn |= (imms & 0x3F) << 10;
insn |= 1 << 22;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_lsr(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let shift = inst.operands[2].get_imm().unwrap_or(0) as u32;
if shift > 63 {
return None;
}
let imms: u32 = 63;
let immr: u32 = shift & 0x3F;
let mut insn: u32 = 0xD3400000;
insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (immr & 0x3F) << 16;
insn |= (imms & 0x3F) << 10;
insn |= 1 << 22;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_asr(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let shift = inst.operands[2].get_imm().unwrap_or(0) as u32;
if shift > 63 {
return None;
}
let imms: u32 = 63;
let immr: u32 = shift & 0x3F;
let mut insn: u32 = 0x9340FC00; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (immr & 0x3F) << 16;
insn |= (imms & 0x3F) << 10;
insn |= 1 << 22;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_sdiv(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let mut insn: u32 = 0x9AC00C00; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_udiv(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let mut insn: u32 = 0x9AC00800; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_csel(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 4 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let cond = inst.operands[3].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x9A800000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (cond & 0xF) << 12;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_adrp(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let imm = inst.operands[1].get_imm().unwrap_or(0) as i64;
let imm_val = imm as u64;
let immlo = (imm_val >> 29) & 0x3;
let immhi = (imm_val >> 5) & 0x7FFFF;
let mut insn: u32 = 0x90000000; insn |= rd & 0x1F;
insn |= (immhi as u32 & 0x7FFFF) << 5;
insn |= (immlo as u32 & 0x3) << 29;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_adr(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let imm = inst.operands[1].get_imm().unwrap_or(0) as i64;
let imm_val = imm as u64;
let immlo = (imm_val >> 29) & 0x3;
let immhi = (imm_val >> 5) & 0x7FFFF;
let mut insn: u32 = 0x10000000; insn |= rd & 0x1F;
insn |= (immhi as u32 & 0x7FFFF) << 5;
insn |= (immlo as u32 & 0x3) << 29;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_add_extended(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let extend = inst.operands.get(3).and_then(|o| o.get_imm()).unwrap_or(3) as u32;
let mut insn: u32 = 0x8B200000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
insn |= (extend & 0x7) << 13;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_movk(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let imm = inst.operands[1].get_imm().unwrap_or(0) as u32;
let hw = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0xF2800000; insn |= rd & 0x1F;
insn |= (imm & 0xFFFF) << 5;
insn |= ((hw / 16) & 0x3) << 21;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_movn(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let imm = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x92800000; insn |= rd & 0x1F;
insn |= (imm & 0xFFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_neg(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rm = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0xCB0003E0; insn |= rd & 0x1F;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_mvn(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rm = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0xAA2003E0; insn |= rd & 0x1F;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_madd(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 4 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let ra = encode_a64_reg(inst.operands[3].get_reg()?);
let mut insn: u32 = 0x9B000000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (ra & 0x1F) << 10;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_clz(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0xDAC01000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_rev(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0xDAC00C00; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= 1 << 10;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_extr(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 4 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let lsb = inst.operands[3].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x93C00000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
insn |= (lsb & 0x3F) << 10;
insn |= 1 << 22;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_bcond(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let offset = inst.operands[0].get_imm().unwrap_or(0) as u32;
let cond = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x54000000; insn |= cond & 0xF;
insn |= (offset & 0x7FFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_cbz(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let offset = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0xB4000000; insn |= rt & 0x1F;
insn |= (offset & 0x7FFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_cbnz(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let offset = inst.operands[1].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0xB5000000; insn |= rt & 0x1F;
insn |= (offset & 0x7FFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_tbz(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let bit = inst.operands[1].get_imm().unwrap_or(0) as u32;
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x36000000; insn |= rt & 0x1F;
insn |= (bit & 0x1F) << 19;
insn |= ((bit >> 5) & 0x1) << 31;
insn |= (offset & 0x3FFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_tbnz(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rt = encode_a64_reg(inst.operands[0].get_reg()?);
let bit = inst.operands[1].get_imm().unwrap_or(0) as u32;
let offset = inst.operands[2].get_imm().unwrap_or(0) as u32;
let mut insn: u32 = 0x37000000; insn |= rt & 0x1F;
insn |= (bit & 0x1F) << 19;
insn |= ((bit >> 5) & 0x1) << 31;
insn |= (offset & 0x3FFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_ret_reg(inst: &MCInst) -> Option<Vec<u8>> {
let rn = if let Some(op) = inst.operands.first() {
encode_a64_reg(op.get_reg()?)
} else {
30
};
let mut insn: u32 = 0xD65F0000; insn |= (rn & 0x1F) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_br(inst: &MCInst) -> Option<Vec<u8>> {
let rn = encode_a64_reg(inst.operands.first()?.get_reg()?);
let mut insn: u32 = 0xD61F0000; insn |= (rn & 0x1F) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_blr(inst: &MCInst) -> Option<Vec<u8>> {
let rn = encode_a64_reg(inst.operands.first()?.get_reg()?);
let mut insn: u32 = 0xD63F0000; insn |= (rn & 0x1F) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_svc(inst: &MCInst) -> Option<Vec<u8>> {
let imm = inst.operands.first().and_then(|o| o.get_imm()).unwrap_or(0) as u32;
let mut insn: u32 = 0xD4000001; insn |= (imm & 0xFFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_brk(inst: &MCInst) -> Option<Vec<u8>> {
let imm = inst.operands.first().and_then(|o| o.get_imm()).unwrap_or(0) as u32;
let mut insn: u32 = 0xD4200000; insn |= (imm & 0xFFFF) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_hint(inst: &MCInst) -> Option<Vec<u8>> {
let imm = inst.operands.first().and_then(|o| o.get_imm()).unwrap_or(0) as u32;
let mut insn: u32 = 0xD503201F; insn |= (imm & 0x7F) << 5;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_isb() -> Vec<u8> {
0xD5033FDFu32.to_le_bytes().to_vec()
}
fn encode_aarch64_dsb() -> Vec<u8> {
0xD5033F9Fu32.to_le_bytes().to_vec()
}
fn encode_aarch64_dmb() -> Vec<u8> {
0xD5033BBFu32.to_le_bytes().to_vec()
}
fn encode_aarch64_msr(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let xt = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0xD500401F; insn |= xt & 0x1F;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_mrs(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let xt = encode_a64_reg(inst.operands[0].get_reg()?);
let mut insn: u32 = 0xD5304000; insn |= xt & 0x1F;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_fadd(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let mut insn: u32 = 0x1E202800; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_fsub(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let mut insn: u32 = 0x1E203800; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_fmul(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let mut insn: u32 = 0x1E200800; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_fdiv(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 3 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let rm = encode_a64_reg(inst.operands[2].get_reg()?);
let mut insn: u32 = 0x1E201800; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_fcmp(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rn = encode_a64_reg(inst.operands[0].get_reg()?);
let rm = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0x1E202000; insn |= (rn & 0x1F) << 5;
insn |= (rm & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
}
fn encode_aarch64_fmov(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
if let Some(rm) = inst.operands[1].get_reg() {
let rm_enc = encode_a64_reg(rm);
let mut insn: u32 = 0x1E204000; insn |= rd & 0x1F;
insn |= (rm_enc & 0x1F) << 16;
Some(insn.to_le_bytes().to_vec())
} else if let Some(imm) = inst.operands[1].get_fpimm() {
let bits = imm.to_bits() as u32;
let mut insn: u32 = 0x1E201000; insn |= rd & 0x1F;
insn |= (bits & 0xFF) << 13; Some(insn.to_le_bytes().to_vec())
} else {
None
}
}
fn encode_aarch64_fcvt(inst: &MCInst) -> Option<Vec<u8>> {
if inst.operands.len() < 2 {
return None;
}
let rd = encode_a64_reg(inst.operands[0].get_reg()?);
let rn = encode_a64_reg(inst.operands[1].get_reg()?);
let mut insn: u32 = 0x1E22C000; insn |= rd & 0x1F;
insn |= (rn & 0x1F) << 5;
Some(insn.to_le_bytes().to_vec())
}
pub fn encode_aarch64_full(inst: &MCInst) -> Option<Vec<u8>> {
match inst.opcode {
0 => Some(encode_aarch64_nop()),
1 => encode_aarch64_mov(inst),
2 => encode_aarch64_add(inst),
3 => encode_aarch64_sub(inst),
4 => encode_aarch64_mul(inst),
5 => encode_aarch64_and(inst),
6 => encode_aarch64_orr(inst),
7 => encode_aarch64_eor(inst),
15 => encode_aarch64_b(inst),
16 => encode_aarch64_bl(inst),
17 => Some(encode_aarch64_ret()),
18 => encode_aarch64_ldr(inst, 1),
19 => encode_aarch64_ldr(inst, 0),
20 => encode_aarch64_str(inst, 1),
21 => encode_aarch64_str(inst, 0),
22 => encode_aarch64_ldp(inst, 1),
23 => encode_aarch64_ldp(inst, 0),
24 => encode_aarch64_stp(inst, 1),
25 => encode_aarch64_stp(inst, 0),
26 => encode_aarch64_cmp(inst),
27 => encode_aarch64_tst(inst),
28 => encode_aarch64_lsl(inst),
29 => encode_aarch64_lsr(inst),
30 => encode_aarch64_asr(inst),
31 => encode_aarch64_sdiv(inst),
32 => encode_aarch64_udiv(inst),
33 => encode_aarch64_csel(inst),
34 => encode_aarch64_adrp(inst),
35 => encode_aarch64_adr(inst),
36 => encode_aarch64_add_extended(inst),
37 => encode_aarch64_movk(inst),
38 => encode_aarch64_movn(inst),
39 => encode_aarch64_neg(inst),
40 => encode_aarch64_mvn(inst),
41 => encode_aarch64_ldrb(inst),
42 => encode_aarch64_strb(inst),
43 => encode_aarch64_ldrh(inst),
44 => encode_aarch64_strh(inst),
45 => encode_aarch64_ldrsw(inst),
46 => encode_aarch64_ldr_literal(inst),
47 => encode_aarch64_madd(inst),
48 => encode_aarch64_msr(inst),
49 => encode_aarch64_mrs(inst),
50 => encode_aarch64_bcond(inst),
51 => encode_aarch64_cbz(inst),
52 => encode_aarch64_cbnz(inst),
53 => encode_aarch64_tbz(inst),
54 => encode_aarch64_tbnz(inst),
55 => encode_aarch64_ret_reg(inst),
56 => encode_aarch64_br(inst),
57 => encode_aarch64_blr(inst),
58 => encode_aarch64_clz(inst),
59 => encode_aarch64_rev(inst),
60 => encode_aarch64_extr(inst),
61 => encode_aarch64_svc(inst),
62 => encode_aarch64_brk(inst),
63 => encode_aarch64_hint(inst),
64 => Some(encode_aarch64_isb()),
65 => Some(encode_aarch64_dsb()),
66 => Some(encode_aarch64_dmb()),
80 => encode_aarch64_fadd(inst),
81 => encode_aarch64_fsub(inst),
82 => encode_aarch64_fmul(inst),
83 => encode_aarch64_fdiv(inst),
84 => encode_aarch64_fcmp(inst),
85 => encode_aarch64_fmov(inst),
86 => encode_aarch64_fcvt(inst),
90 => encode_aarch64_ldr(inst, 2),
91 => encode_aarch64_str(inst, 2),
92 => encode_aarch64_ldp(inst, 2),
93 => encode_aarch64_stp(inst, 2),
94 => encode_aarch64_ldp(inst, 3),
95 => encode_aarch64_stp(inst, 3),
_ => None,
}
}
fn rv_push_u32_le(insn: u32) -> Vec<u8> {
insn.to_le_bytes().to_vec()
}
fn encode_riscv_r(opcode: u32, rd: u32, funct3: u32, rs1: u32, rs2: u32, funct7: u32) -> u32 {
(funct7 & 0x7F) << 25
| (rs2 & 0x1F) << 20
| (rs1 & 0x1F) << 15
| (funct3 & 0x7) << 12
| (rd & 0x1F) << 7
| (opcode & 0x7F)
}
fn encode_riscv_i(opcode: u32, rd: u32, funct3: u32, rs1: u32, imm: i32) -> u32 {
((imm as u32) & 0xFFF) << 20
| (rs1 & 0x1F) << 15
| (funct3 & 0x7) << 12
| (rd & 0x1F) << 7
| (opcode & 0x7F)
}
fn encode_riscv_s(opcode: u32, funct3: u32, rs1: u32, rs2: u32, imm: i32) -> u32 {
let imm_u = imm as u32;
((imm_u >> 5) & 0x7F) << 25
| (rs2 & 0x1F) << 20
| (rs1 & 0x1F) << 15
| (funct3 & 0x7) << 12
| (imm_u & 0x1F) << 7
| (opcode & 0x7F)
}
fn encode_riscv_b(opcode: u32, funct3: u32, rs1: u32, rs2: u32, imm: i32) -> u32 {
let imm_u = imm as u32;
((imm_u >> 12) & 0x1) << 31
| ((imm_u >> 5) & 0x3F) << 25
| (rs2 & 0x1F) << 20
| (rs1 & 0x1F) << 15
| (funct3 & 0x7) << 12
| ((imm_u >> 1) & 0xF) << 8
| ((imm_u >> 11) & 0x1) << 7
| (opcode & 0x7F)
}
fn encode_riscv_u(opcode: u32, rd: u32, imm: i32) -> u32 {
((imm as u32) & 0xFFFFF000) | (rd & 0x1F) << 7 | (opcode & 0x7F)
}
fn encode_riscv_j(opcode: u32, rd: u32, imm: i32) -> u32 {
let imm_u = imm as u32;
((imm_u >> 20) & 0x1) << 31
| ((imm_u >> 1) & 0x3FF) << 21
| ((imm_u >> 11) & 0x1) << 20
| ((imm_u >> 12) & 0xFF) << 12
| (rd & 0x1F) << 7
| (opcode & 0x7F)
}
const RV_OP_LUI: u32 = 0b0110111;
const RV_OP_AUIPC: u32 = 0b0010111;
const RV_OP_JAL: u32 = 0b1101111;
const RV_OP_JALR: u32 = 0b1100111;
const RV_OP_BRANCH: u32 = 0b1100011;
const RV_OP_LOAD: u32 = 0b0000011;
const RV_OP_STORE: u32 = 0b0100011;
const RV_OP_IMM: u32 = 0b0010011;
const RV_OP_OP: u32 = 0b0110011;
const RV_OP_SYSTEM: u32 = 0b1110011;
const RV_OP_MISC: u32 = 0b0001111;
const RV_OP_IMM32: u32 = 0b0011011;
const RV_OP_OP32: u32 = 0b0111011;
fn encode_rv_reg(reg: u32) -> u32 {
reg & 0x1F
}
fn rv_get_imm(inst: &MCInst, idx: usize) -> i64 {
inst.operands
.get(idx)
.and_then(|o| o.get_imm())
.unwrap_or(0)
}
fn rv_get_reg(inst: &MCInst, idx: usize) -> u32 {
inst.operands
.get(idx)
.and_then(|o| o.get_reg())
.unwrap_or(0)
}
pub fn encode_riscv(inst: &MCInst) -> Option<Vec<u8>> {
match inst.opcode {
1 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b000, rs1, rs2, 0b0000000,
)))
}
2 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b000, rs1, rs2, 0b0100000,
)))
}
3 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b001, rs1, rs2, 0b0000000,
)))
}
4 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b010, rs1, rs2, 0b0000000,
)))
}
5 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b011, rs1, rs2, 0b0000000,
)))
}
6 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b100, rs1, rs2, 0b0000000,
)))
}
7 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b101, rs1, rs2, 0b0000000,
)))
}
8 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b101, rs1, rs2, 0b0100000,
)))
}
9 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b110, rs1, rs2, 0b0000000,
)))
}
10 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b111, rs1, rs2, 0b0000000,
)))
}
11 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b000, rs1, rs2, 0b0000000,
)))
}
12 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b000, rs1, rs2, 0b0100000,
)))
}
13 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b001, rs1, rs2, 0b0000000,
)))
}
14 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b101, rs1, rs2, 0b0000000,
)))
}
15 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b101, rs1, rs2, 0b0100000,
)))
}
20 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_IMM, rd, 0b000, rs1, imm,
)))
}
21 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_IMM, rd, 0b010, rs1, imm,
)))
}
22 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_IMM, rd, 0b011, rs1, imm,
)))
}
23 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_IMM, rd, 0b100, rs1, imm,
)))
}
24 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_IMM, rd, 0b110, rs1, imm,
)))
}
25 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_IMM, rd, 0b111, rs1, imm,
)))
}
30 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let shamt = rv_get_imm(inst, 2) as u32;
let imm = ((shamt & 0x3F) as u32) | 0x000;
let insn = (imm << 20) | (rs1 << 15) | (0b001 << 12) | (rd << 7) | RV_OP_IMM;
Some(rv_push_u32_le(insn))
}
31 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let shamt = rv_get_imm(inst, 2) as u32;
let imm = ((shamt & 0x3F) as u32) | 0x000;
let insn = (imm << 20) | (rs1 << 15) | (0b101 << 12) | (rd << 7) | RV_OP_IMM;
Some(rv_push_u32_le(insn))
}
32 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let shamt = rv_get_imm(inst, 2) as u32;
let imm = ((shamt & 0x3F) as u32) | 0x400;
let insn = (imm << 20) | (rs1 << 15) | (0b101 << 12) | (rd << 7) | RV_OP_IMM;
Some(rv_push_u32_le(insn))
}
33 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let shamt = rv_get_imm(inst, 2) as u32;
let imm = ((shamt & 0x1F) as u32) | 0x000;
let insn = (imm << 20) | (rs1 << 15) | (0b001 << 12) | (rd << 7) | RV_OP_IMM32;
Some(rv_push_u32_le(insn))
}
34 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let shamt = rv_get_imm(inst, 2) as u32;
let imm = ((shamt & 0x1F) as u32) | 0x000;
let insn = (imm << 20) | (rs1 << 15) | (0b101 << 12) | (rd << 7) | RV_OP_IMM32;
Some(rv_push_u32_le(insn))
}
35 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let shamt = rv_get_imm(inst, 2) as u32;
let imm = ((shamt & 0x1F) as u32) | 0x400;
let insn = (imm << 20) | (rs1 << 15) | (0b101 << 12) | (rd << 7) | RV_OP_IMM32;
Some(rv_push_u32_le(insn))
}
40 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b000, rs1, imm,
)))
}
41 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b001, rs1, imm,
)))
}
42 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b010, rs1, imm,
)))
}
43 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b100, rs1, imm,
)))
}
44 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b101, rs1, imm,
)))
}
45 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b011, rs1, imm,
)))
}
46 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_LOAD, rd, 0b110, rs1, imm,
)))
}
50 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_s(
RV_OP_STORE,
0b000,
rs1,
rs2,
imm,
)))
}
51 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_s(
RV_OP_STORE,
0b001,
rs1,
rs2,
imm,
)))
}
52 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_s(
RV_OP_STORE,
0b010,
rs1,
rs2,
imm,
)))
}
53 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_s(
RV_OP_STORE,
0b011,
rs1,
rs2,
imm,
)))
}
60 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_b(
RV_OP_BRANCH,
0b000,
rs1,
rs2,
imm,
)))
}
61 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_b(
RV_OP_BRANCH,
0b001,
rs1,
rs2,
imm,
)))
}
62 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_b(
RV_OP_BRANCH,
0b100,
rs1,
rs2,
imm,
)))
}
63 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_b(
RV_OP_BRANCH,
0b101,
rs1,
rs2,
imm,
)))
}
64 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_b(
RV_OP_BRANCH,
0b110,
rs1,
rs2,
imm,
)))
}
65 => {
let rs1 = encode_rv_reg(rv_get_reg(inst, 0));
let rs2 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_b(
RV_OP_BRANCH,
0b111,
rs1,
rs2,
imm,
)))
}
70 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as i32;
Some(rv_push_u32_le(encode_riscv_j(RV_OP_JAL, rd, imm)))
}
71 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let imm = rv_get_imm(inst, 2) as i32;
Some(rv_push_u32_le(encode_riscv_i(
RV_OP_JALR, rd, 0b000, rs1, imm,
)))
}
80 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as i32;
Some(rv_push_u32_le(encode_riscv_u(RV_OP_LUI, rd, imm)))
}
81 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as i32;
Some(rv_push_u32_le(encode_riscv_u(RV_OP_AUIPC, rd, imm)))
}
90 => Some(rv_push_u32_le(0x00000073)), 91 => Some(rv_push_u32_le(0x00100073)), 92 => {
let pred = rv_get_imm(inst, 0) as u32 & 0xF;
let succ = rv_get_imm(inst, 1) as u32 & 0xF;
let insn = (0b0000 << 28)
| (pred << 24)
| (succ << 20)
| (0b00000 << 15)
| (0b000 << 12)
| (0b00000 << 7)
| RV_OP_MISC;
Some(rv_push_u32_le(insn))
}
93 => Some(rv_push_u32_le(0x0000100F)),
100 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b000, rs1, rs2, 0b0000001,
)))
}
101 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b001, rs1, rs2, 0b0000001,
)))
}
102 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b010, rs1, rs2, 0b0000001,
)))
}
103 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b011, rs1, rs2, 0b0000001,
)))
}
104 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b100, rs1, rs2, 0b0000001,
)))
}
105 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b101, rs1, rs2, 0b0000001,
)))
}
106 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b110, rs1, rs2, 0b0000001,
)))
}
107 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP, rd, 0b111, rs1, rs2, 0b0000001,
)))
}
108 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b000, rs1, rs2, 0b0000001,
)))
}
109 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b100, rs1, rs2, 0b0000001,
)))
}
110 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b101, rs1, rs2, 0b0000001,
)))
}
111 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b110, rs1, rs2, 0b0000001,
)))
}
112 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let rs1 = encode_rv_reg(rv_get_reg(inst, 1));
let rs2 = encode_rv_reg(rv_get_reg(inst, 2));
Some(rv_push_u32_le(encode_riscv_r(
RV_OP_OP32, rd, 0b111, rs1, rs2, 0b0000001,
)))
}
500 => Some(vec![0x01, 0x00]), 501 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as u32;
let insn: u16 = ((0x0000u32 | ((rd & 0x7) << 2) | ((imm & 0x3F) << 5) | 0b00) as u16);
Some(insn.to_le_bytes().to_vec())
}
502 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as i8;
let i = imm as u8;
let insn: u16 = ((0x0001u32
| ((rd & 0x1F) << 7)
| ((((i >> 5) & 0x1) as u32) << 12)
| (((i & 0x1F) as u32) << 2)) as u16);
Some(insn.to_le_bytes().to_vec())
}
503 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as i8;
let i = imm as u8;
let insn: u16 = ((0x4001u32
| ((rd & 0x1F) << 7)
| ((((i >> 5) & 0x1) as u32) << 12)
| (((i & 0x1F) as u32) << 2)) as u16);
Some(insn.to_le_bytes().to_vec())
}
504 => {
let rd = encode_rv_reg(rv_get_reg(inst, 0));
let imm = rv_get_imm(inst, 1) as u32;
let insn: u16 = ((0x6001u32
| ((rd & 0x1F) << 7)
| (((imm >> 17) & 0x1) << 12)
| (((imm >> 12) & 0x1F) << 2)) as u16);
Some(insn.to_le_bytes().to_vec())
}
505 => {
let imm = rv_get_imm(inst, 0) as i16;
let i = imm as u16;
let insn: u16 = ((0xA001u32
| (((i as u32 >> 11) & 0x1) << 12)
| (((i as u32 >> 4) & 0x1) << 11)
| (((i as u32 >> 9) & 0x3) << 9)
| (((i as u32 >> 8) & 0x1) << 8)
| (((i as u32 >> 10) & 0x1) << 7)
| (((i as u32 >> 6) & 0x1) << 6)
| (((i as u32 >> 7) & 0x1) << 5)
| (((i as u32 >> 3) & 0x3) << 3)
| (((i as u32 >> 1) & 0x3) << 1)) as u16);
Some(insn.to_le_bytes().to_vec())
}
_ => None,
}
}
pub fn encode_m68k(_inst: &MCInst) -> Option<Vec<u8>> {
None
}
fn encode_m68k_nop() -> Vec<u8> {
vec![0x4E, 0x71]
}
fn encode_m68k_rts() -> Vec<u8> {
vec![0x4E, 0x75]
}
fn encode_m68k_rte() -> Vec<u8> {
vec![0x4E, 0x73]
}
fn encode_m68k_trap(vector: u8) -> Vec<u8> {
vec![0x4E, 0x40 | (vector & 0xF)]
}
fn encode_m68k_move_w(dst: u8, src: u8) -> Vec<u8> {
let word: u16 = 0x3000 | ((dst as u16 & 0x7) << 9) | (src as u16 & 0x7);
word.to_be_bytes().to_vec()
}
fn encode_m68k_move_l(dst: u8, src: u8) -> Vec<u8> {
let word: u16 = 0x2000 | ((dst as u16 & 0x7) << 9) | (src as u16 & 0x7);
word.to_be_bytes().to_vec()
}
fn encode_m68k_add_l(dst: u8, src: u8) -> Vec<u8> {
let word: u16 = 0xD080 | ((dst as u16 & 0x7) << 9) | (src as u16 & 0x7);
word.to_be_bytes().to_vec()
}
fn encode_m68k_sub_l(dst: u8, src: u8) -> Vec<u8> {
let word: u16 = 0x9080 | ((dst as u16 & 0x7) << 9) | (src as u16 & 0x7);
word.to_be_bytes().to_vec()
}
fn encode_m68k_cmp_l(dst: u8, src: u8) -> Vec<u8> {
let word: u16 = 0xB080 | ((src as u16 & 0x7) << 9) | (dst as u16 & 0x7);
word.to_be_bytes().to_vec()
}
fn encode_m68k_bra(disp: i8) -> Vec<u8> {
let word: u16 = 0x6000 | (disp as u8 as u16);
word.to_be_bytes().to_vec()
}
fn encode_m68k_bsr(disp: i8) -> Vec<u8> {
let word: u16 = 0x6100 | (disp as u8 as u16);
word.to_be_bytes().to_vec()
}
fn encode_m68k_jmp_an(reg: u8) -> Vec<u8> {
let word: u16 = 0x4ED0 | ((reg as u16 & 0x7) << 9);
word.to_be_bytes().to_vec()
}
fn encode_m68k_jsr_an(reg: u8) -> Vec<u8> {
let word: u16 = 0x4E90 | ((reg as u16 & 0x7) << 9);
word.to_be_bytes().to_vec()
}
pub fn encode_immediate(value: i64, bits: u32, signed: bool) -> Option<u64> {
if signed {
let min = -(1i64 << (bits - 1));
let max = (1i64 << (bits - 1)) - 1;
if value < min || value > max {
return None;
}
let mask = (1u64 << bits) - 1;
Some((value as u64) & mask)
} else {
if value < 0 {
return None;
}
let max = (1u64 << bits) - 1;
if (value as u64) > max {
return None;
}
Some(value as u64)
}
}
pub fn encode_register(reg: u32, target: &str) -> u32 {
match target {
"x86_64" => reg & 0xF,
"aarch64" => reg & 0x1F,
"arm32" => reg & 0xF,
"riscv" => reg & 0x1F,
_ => 0,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum A64Condition {
EQ = 0b0000,
NE = 0b0001,
CS = 0b0010,
CC = 0b0011,
MI = 0b0100,
PL = 0b0101,
VS = 0b0110,
VC = 0b0111,
HI = 0b1000,
LS = 0b1001,
GE = 0b1010,
LT = 0b1011,
GT = 0b1100,
LE = 0b1101,
AL = 0b1110,
NV = 0b1111,
}
impl A64Condition {
pub fn from_name(name: &str) -> Option<Self> {
match name.to_uppercase().as_str() {
"EQ" => Some(Self::EQ),
"NE" => Some(Self::NE),
"CS" | "HS" => Some(Self::CS),
"CC" | "LO" => Some(Self::CC),
"MI" => Some(Self::MI),
"PL" => Some(Self::PL),
"VS" => Some(Self::VS),
"VC" => Some(Self::VC),
"HI" => Some(Self::HI),
"LS" => Some(Self::LS),
"GE" => Some(Self::GE),
"LT" => Some(Self::LT),
"GT" => Some(Self::GT),
"LE" => Some(Self::LE),
"AL" => Some(Self::AL),
"NV" => Some(Self::NV),
_ => None,
}
}
pub fn bits(self) -> u32 {
self as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum A64Shift {
LSL = 0b00,
LSR = 0b01,
ASR = 0b10,
ROR = 0b11,
}
impl A64Shift {
pub fn from_name(name: &str) -> Option<Self> {
match name.to_uppercase().as_str() {
"LSL" => Some(Self::LSL),
"LSR" => Some(Self::LSR),
"ASR" => Some(Self::ASR),
"ROR" => Some(Self::ROR),
_ => None,
}
}
pub fn bits(self) -> u32 {
self as u32
}
}
pub fn encode_condition(cond: &str, target: &str) -> Option<u32> {
match target {
"aarch64" => A64Condition::from_name(cond).map(|c| c.bits()),
"arm32" => {
if let Some(c) = A64Condition::from_name(cond) {
Some((c.bits() & 0xF) << 28)
} else {
cond.parse::<u32>().ok().map(|v| (v & 0xF) << 28)
}
}
_ => Some(0),
}
}
pub fn encode_aarch64_shift(shift_type: &str, amount: u32) -> Option<(u32, u32)> {
let st = A64Shift::from_name(shift_type)?;
if amount > 63 {
return None;
}
Some((st.bits(), amount & 0x3F))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelocationKind {
Abs32,
Abs64,
PcRel32,
GotPcRel,
Plt32,
Copy,
GlobDat,
JumpSlot,
Relative,
TlsGd,
TlsLd,
TlsIe,
TlsLe,
}
#[derive(Debug, Clone)]
pub struct RelocationResult {
pub value: u64,
pub size: u8,
pub is_pc_relative: bool,
}
pub fn apply_relocation(
kind: RelocationKind,
S: u64,
A: u64,
P: u64,
G: u64,
L: u64,
B: u64,
) -> RelocationResult {
match kind {
RelocationKind::Abs32 => RelocationResult {
value: S.wrapping_add(A) as u32 as u64,
size: 4,
is_pc_relative: false,
},
RelocationKind::Abs64 => RelocationResult {
value: S.wrapping_add(A),
size: 8,
is_pc_relative: false,
},
RelocationKind::PcRel32 => {
let val = S.wrapping_add(A).wrapping_sub(P) as i64;
RelocationResult {
value: val as u32 as u64,
size: 4,
is_pc_relative: true,
}
}
RelocationKind::GotPcRel => {
let val = G.wrapping_add(A).wrapping_sub(P) as i64;
RelocationResult {
value: val as u32 as u64,
size: 4,
is_pc_relative: true,
}
}
RelocationKind::Plt32 => {
let val = L.wrapping_add(A).wrapping_sub(P) as i64;
RelocationResult {
value: val as u32 as u64,
size: 4,
is_pc_relative: true,
}
}
RelocationKind::Copy => RelocationResult {
value: S,
size: 8,
is_pc_relative: false,
},
RelocationKind::GlobDat => RelocationResult {
value: S.wrapping_add(A),
size: 8,
is_pc_relative: false,
},
RelocationKind::JumpSlot => RelocationResult {
value: S,
size: 8,
is_pc_relative: false,
},
RelocationKind::Relative => RelocationResult {
value: B.wrapping_add(A),
size: 8,
is_pc_relative: false,
},
RelocationKind::TlsGd => RelocationResult {
value: 0,
size: 8,
is_pc_relative: false,
},
RelocationKind::TlsLd => RelocationResult {
value: 0,
size: 8,
is_pc_relative: false,
},
RelocationKind::TlsIe => RelocationResult {
value: 0,
size: 8,
is_pc_relative: false,
},
RelocationKind::TlsLe => RelocationResult {
value: 0,
size: 8,
is_pc_relative: false,
},
}
}
pub fn elf_relocation_kind(elf_type: u32) -> Option<RelocationKind> {
match elf_type {
1 => Some(RelocationKind::Abs32),
2 => Some(RelocationKind::Copy),
3 => Some(RelocationKind::GlobDat),
4 => Some(RelocationKind::JumpSlot),
5 => Some(RelocationKind::Relative),
6 => Some(RelocationKind::GotPcRel),
7 => Some(RelocationKind::Plt32),
8 => Some(RelocationKind::Abs64),
_ => None,
}
}
pub fn x86_64_relocation_kind(elf_type: u32) -> Option<RelocationKind> {
match elf_type {
1 => Some(RelocationKind::Abs64),
2 => Some(RelocationKind::PcRel32),
3 => Some(RelocationKind::GotPcRel),
4 => Some(RelocationKind::Plt32),
5 => Some(RelocationKind::Copy),
6 => Some(RelocationKind::GlobDat),
7 => Some(RelocationKind::JumpSlot),
8 => Some(RelocationKind::Relative),
10 => Some(RelocationKind::Abs32),
16 => Some(RelocationKind::TlsGd),
17 => Some(RelocationKind::TlsLd),
18 => Some(RelocationKind::TlsIe),
19 => Some(RelocationKind::TlsLe),
_ => None,
}
}
pub fn write_relocation_value(buf: &mut [u8], offset: usize, reloc: &RelocationResult) {
if offset + reloc.size as usize > buf.len() {
return;
}
match reloc.size {
4 => {
let val = reloc.value as u32;
buf[offset..offset + 4].copy_from_slice(&val.to_le_bytes());
}
8 => {
buf[offset..offset + 8].copy_from_slice(&reloc.value.to_le_bytes());
}
_ => {}
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use super::*;
use crate::mc_inst::{MCInst, MCOperand};
use crate::mc_streamer::x86_opcodes;
#[test]
fn test_encode_nop() {
let inst = MCInst::new(x86_opcodes::NOP);
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x90]);
}
#[test]
fn test_encode_ret() {
let inst = MCInst::new(x86_opcodes::RET);
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0xC3]);
}
#[test]
fn test_encode_ret_imm16() {
let mut inst = MCInst::new(x86_opcodes::RET);
inst.add_operand(MCOperand::imm(8));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0xC2, 0x08, 0x00]);
}
#[test]
fn test_encode_push_r64() {
let mut inst = MCInst::new(x86_opcodes::PUSH);
inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x50]);
let mut inst = MCInst::new(x86_opcodes::PUSH);
inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x51]);
let mut inst = MCInst::new(x86_opcodes::PUSH);
inst.add_operand(MCOperand::reg(8)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x41, 0x50]);
}
#[test]
fn test_encode_pop_r64() {
let mut inst = MCInst::new(x86_opcodes::POP);
inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x58]);
let mut inst = MCInst::new(x86_opcodes::POP);
inst.add_operand(MCOperand::reg(7)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x5F]);
}
#[test]
fn test_encode_mov_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::MOV);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0x89, 0xC8]);
}
#[test]
fn test_encode_mov_r64_imm64() {
let mut inst = MCInst::new(x86_opcodes::MOV);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::imm(42));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded.len(), 10);
assert_eq!(encoded[0], 0x48); assert_eq!(encoded[1], 0xB8); let imm = i64::from_le_bytes(encoded[2..10].try_into().unwrap());
assert_eq!(imm, 42);
}
#[test]
fn test_encode_add_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::ADD);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded.len(), 3);
assert_eq!(encoded[0], 0x48); assert_eq!(encoded[1], 0x01); assert_eq!(encoded[2], 0xC1);
}
#[test]
fn test_encode_sub_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::SUB);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded.len(), 3);
assert_eq!(encoded[0], 0x48); assert_eq!(encoded[1], 0x29); assert_eq!(encoded[2], 0xC1);
}
#[test]
fn test_encode_add_r32_imm8() {
let mut inst = MCInst::new(x86_opcodes::ADD);
inst.size = 4;
inst.add_operand(MCOperand::reg(16)); inst.add_operand(MCOperand::imm(1));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded[0], 0x83);
assert_eq!(encoded[1], 0xC0);
assert_eq!(encoded[2], 0x01);
}
#[test]
fn test_encode_sub_r32_imm8() {
let mut inst = MCInst::new(x86_opcodes::SUB);
inst.size = 4;
inst.add_operand(MCOperand::reg(16)); inst.add_operand(MCOperand::imm(1));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded[0], 0x83);
assert_eq!(encoded[1], 0xE8); assert_eq!(encoded[2], 0x01);
}
#[test]
fn test_encode_add_r64_imm32() {
let mut inst = MCInst::new(x86_opcodes::ADD);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::imm(1000));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded[0], 0x48); assert_eq!(encoded[1], 0x81); assert_eq!(encoded[2], 0xC0); let imm = i32::from_le_bytes(encoded[3..7].try_into().unwrap());
assert_eq!(imm, 1000);
}
#[test]
fn test_encode_jmp_rel32() {
let mut inst = MCInst::new(x86_opcodes::JMP);
inst.add_operand(MCOperand::imm(42));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0xE9, 0x2A, 0x00, 0x00, 0x00]);
}
#[test]
fn test_encode_call_rel32() {
let mut inst = MCInst::new(x86_opcodes::CALL);
inst.add_operand(MCOperand::imm(100));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0xE8, 0x64, 0x00, 0x00, 0x00]);
}
#[test]
fn test_encode_cmp_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::CMP);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded.len(), 3);
assert_eq!(encoded[0], 0x48);
assert_eq!(encoded[1], 0x39);
assert_eq!(encoded[2], 0xC1);
}
#[test]
fn test_encode_push_r12() {
let mut inst = MCInst::new(x86_opcodes::PUSH);
inst.add_operand(MCOperand::reg(12)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x41, 0x54]);
}
#[test]
fn test_encode_xor_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::XOR);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0x31, 0xC0]);
}
#[test]
fn test_encode_and_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::AND);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0x21, 0xC1]);
}
#[test]
fn test_encode_or_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::OR);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0x09, 0xC1]);
}
#[test]
fn test_encode_mul_r64() {
let mut inst = MCInst::new(x86_opcodes::MUL);
inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xF7, 0xE1]);
}
#[test]
fn test_encode_inc_r64() {
let mut inst = MCInst::new(x86_opcodes::INC);
inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xFF, 0xC0]);
}
#[test]
fn test_encode_dec_r64() {
let mut inst = MCInst::new(x86_opcodes::DEC);
inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xFF, 0xC8]);
}
#[test]
fn test_encode_not_r64() {
let mut inst = MCInst::new(x86_opcodes::NOT);
inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xF7, 0xD0]);
}
#[test]
fn test_encode_neg_r64() {
let mut inst = MCInst::new(x86_opcodes::NEG);
inst.add_operand(MCOperand::reg(0)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xF7, 0xD8]);
}
#[test]
fn test_encode_shl_r64_cl() {
let mut inst = MCInst::new(x86_opcodes::SHL);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xD3, 0xE0]);
}
#[test]
fn test_encode_shl_r64_imm8() {
let mut inst = MCInst::new(x86_opcodes::SHL);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::imm(3));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xC1, 0xE0, 0x03]);
}
#[test]
fn test_encode_shr_r64_imm8() {
let mut inst = MCInst::new(x86_opcodes::SHR);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::imm(2));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xC1, 0xE8, 0x02]);
}
#[test]
fn test_encode_div_r64() {
let mut inst = MCInst::new(x86_opcodes::DIV);
inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x48, 0xF7, 0xF1]);
}
#[test]
fn test_encode_je_rel32() {
let mut inst = MCInst::new(x86_opcodes::JE);
inst.add_operand(MCOperand::imm(42));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x0F, 0x84, 0x2A, 0x00, 0x00, 0x00]);
}
#[test]
fn test_encode_jne_rel32() {
let mut inst = MCInst::new(x86_opcodes::JNE);
inst.add_operand(MCOperand::imm(42));
let encoded = encode_x86_64(&inst).unwrap();
assert_eq!(encoded, vec![0x0F, 0x85, 0x2A, 0x00, 0x00, 0x00]);
}
#[test]
fn test_encode_aarch64_nop() {
let inst = MCInst::new(0); let encoded = encode_aarch64(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_aarch64_ret() {
let inst = MCInst::new(17); let encoded = encode_aarch64(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_aarch64_mov() {
let mut inst = MCInst::new(1); inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::imm(42));
let encoded = encode_aarch64(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_aarch64_add() {
let mut inst = MCInst::new(2); inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); inst.add_operand(MCOperand::imm(5));
let encoded = encode_aarch64(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_aarch64_sub() {
let mut inst = MCInst::new(3); inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); inst.add_operand(MCOperand::imm(3));
let encoded = encode_aarch64(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_arm32_nop() {
let inst = MCInst::new(0); let encoded = encode_arm32(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_arm32_mov() {
let mut inst = MCInst::new(1); inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_arm32(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_encode_arm32_add() {
let mut inst = MCInst::new(4); inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); inst.add_operand(MCOperand::reg(2)); let encoded = encode_arm32(&inst).unwrap();
assert_eq!(encoded.len(), 4);
}
#[test]
fn test_assembler_section_management() {
let mut asm = MCAssembler::new("x86_64-unknown-linux-gnu");
let text_idx = asm.get_or_create_section(".text", SectionType::Text);
let data_idx = asm.get_or_create_section(".data", SectionType::Data);
assert_ne!(text_idx, data_idx);
assert_eq!(
asm.get_or_create_section(".text", SectionType::Text),
text_idx
);
}
#[test]
fn test_assembler_emit_instruction() {
let mut asm = MCAssembler::new("x86_64-unknown-linux-gnu");
asm.emit_instruction(vec![0x90]); asm.emit_instruction(vec![0xC3]); let flat = asm.flatten_section(0);
assert_eq!(flat, vec![0x90, 0xC3]);
}
#[test]
fn test_assembler_flatten_all() {
let mut asm = MCAssembler::new("x86_64-unknown-linux-gnu");
asm.emit_instruction(vec![0x90, 0xC3]); asm.emit_data(vec![0xDE, 0xAD, 0xBE, 0xEF], ".rodata");
let (total, offsets) = asm.flatten_all();
assert_eq!(total.len(), 6);
assert_eq!(offsets.len(), 2);
}
#[test]
fn test_assembler_symbol_definition() {
let mut asm = MCAssembler::new("x86_64-unknown-linux-gnu");
asm.emit_instruction(vec![0x90]);
let sec = asm.get_or_create_section(".text", SectionType::Text);
asm.define_symbol("main", sec, 0, 0);
assert_eq!(asm.symbols.len(), 1);
assert_eq!(asm.symbols[0].0, "main");
}
#[test]
fn test_roundtrip_x86_nop() {
let inst = MCInst::new(x86_opcodes::NOP);
let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::NOP);
assert_eq!(decoded.size, 1);
}
#[test]
fn test_roundtrip_x86_ret() {
let inst = MCInst::new(x86_opcodes::RET);
let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::RET);
assert_eq!(decoded.size, 1);
}
#[test]
fn test_roundtrip_x86_push_r64() {
for reg in 0..8u32 {
let mut inst = MCInst::new(x86_opcodes::PUSH);
inst.add_operand(MCOperand::reg(reg));
let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::PUSH);
assert_eq!(
decoded.inst.operands[0].get_reg().unwrap(),
reg,
"push r{} roundtrip failed",
reg
);
}
}
#[test]
fn test_roundtrip_x86_pop_r64() {
for reg in 0..8u32 {
let mut inst = MCInst::new(x86_opcodes::POP);
inst.add_operand(MCOperand::reg(reg));
let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::POP);
assert_eq!(
decoded.inst.operands[0].get_reg().unwrap(),
reg,
"pop r{} roundtrip failed",
reg
);
}
}
#[test]
fn test_roundtrip_x86_mov_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::MOV);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::MOV);
assert_eq!(decoded.inst.operands.len(), 2);
}
#[test]
fn test_roundtrip_x86_add_sub_r64_r64() {
let mut inst = MCInst::new(x86_opcodes::ADD);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::reg(1)); let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::ADD);
let mut inst = MCInst::new(x86_opcodes::SUB);
inst.add_operand(MCOperand::reg(0));
inst.add_operand(MCOperand::reg(1));
let encoded = encode_x86_64(&inst).unwrap();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::SUB);
}
#[test]
fn test_roundtrip_x86_mov_r64_imm64() {
let mut inst = MCInst::new(x86_opcodes::MOV);
inst.add_operand(MCOperand::reg(0)); inst.add_operand(MCOperand::imm(0xDEADBEEF));
let encoded = encode_x86_64(&inst).unwrap();
let disasm = crate::mc_disassembler::X86Disassembler::new();
let decoded = disasm.decode_one(&encoded, 0).unwrap();
assert_eq!(decoded.inst.opcode, x86_opcodes::MOV);
assert_eq!(decoded.inst.operands[0].get_reg().unwrap(), 0); assert_eq!(decoded.inst.operands[1].get_imm().unwrap(), 0xDEADBEEF);
}
}