use crate::{
BasicBlock, ImmediateDesc, Instruction, Op, Operand, RegisterDesc, RegisterFlags, Vip,
};
use std::convert::TryInto;
const VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN: usize = 2;
pub struct InstructionBuilder<'a> {
basic_block: &'a mut BasicBlock,
}
fn insert_instr(basic_block: &mut BasicBlock, op: Op) {
basic_block.instructions.push(Instruction {
op,
vip: Vip::invalid(),
sp_offset: basic_block.sp_offset,
sp_index: basic_block.sp_index,
sp_reset: false,
});
}
impl<'a> InstructionBuilder<'a> {
pub fn from(basic_block: &'a mut BasicBlock) -> InstructionBuilder<'a> {
InstructionBuilder { basic_block }
}
pub fn shift_sp(&mut self, offset: i64) {
self.basic_block.sp_offset += offset;
}
pub fn push(&mut self, op1: Operand) -> &mut Self {
if let Operand::RegisterDesc(sp) = op1 {
if sp.flags.contains(RegisterFlags::STACK_POINTER) {
let tmp0 = self.basic_block.tmp(64);
self.mov(tmp0, op1).push(tmp0.into());
return self;
}
}
let misalignment = (op1.size() % VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN) as i64;
if misalignment != 0 {
let padding_size = VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN as i64 - misalignment;
self.shift_sp(-padding_size);
self.str(
RegisterDesc::SP,
self.basic_block.sp_offset.into(),
ImmediateDesc::new(0u64, TryInto::<u32>::try_into(padding_size).unwrap() * 8)
.into(),
);
}
self.shift_sp(-(op1.size() as i64));
self.str(RegisterDesc::SP, self.basic_block.sp_offset.into(), op1);
self
}
pub fn pop(&mut self, op1: RegisterDesc) -> &mut Self {
let offset = self.basic_block.sp_offset;
let misalignment = (op1.size() % VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN) as i64;
if misalignment != 0 {
self.shift_sp(VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN as i64 - misalignment);
}
self.shift_sp(op1.size() as i64);
self.ldd(op1, RegisterDesc::SP, offset.into());
self
}
pub fn pushf(&mut self) -> &mut Self {
self.push(RegisterDesc::FLAGS.into())
}
pub fn popf(&mut self) -> &mut Self {
self.push(RegisterDesc::FLAGS.into())
}
pub fn mov(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Mov(op1.into(), op2.into()));
self
}
pub fn movsx(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Movsx(op1.into(), op2.into()));
self
}
pub fn str(&mut self, op1: RegisterDesc, op2: ImmediateDesc, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Str(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn ldd(&mut self, op1: RegisterDesc, op2: RegisterDesc, op3: ImmediateDesc) -> &mut Self {
insert_instr(
self.basic_block,
Op::Ldd(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn neg(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Neg(op1.into()));
self
}
pub fn add(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Add(op1.into(), op2.into()));
self
}
pub fn sub(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Sub(op1.into(), op2.into()));
self
}
pub fn mul(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Mul(op1.into(), op2.into()));
self
}
pub fn mulhi(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Mulhi(op1.into(), op2.into()));
self
}
pub fn imul(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Imul(op1.into(), op2.into()));
self
}
pub fn imulhi(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Imulhi(op1.into(), op2.into()));
self
}
pub fn div(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Div(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn rem(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Rem(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn idiv(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Idiv(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn irem(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Irem(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn popcnt(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Popcnt(op1.into()));
self
}
pub fn bsf(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Bsf(op1.into()));
self
}
pub fn bsr(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Bsr(op1.into()));
self
}
pub fn not(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Not(op1.into()));
self
}
pub fn shr(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Shr(op1.into(), op2.into()));
self
}
pub fn shl(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Shl(op1.into(), op2.into()));
self
}
pub fn xor(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Xor(op1.into(), op2.into()));
self
}
pub fn or(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Or(op1.into(), op2.into()));
self
}
pub fn and(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::And(op1.into(), op2.into()));
self
}
pub fn ror(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Ror(op1.into(), op2.into()));
self
}
pub fn rol(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Rol(op1.into(), op2.into()));
self
}
pub fn tg(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Tg(op1.into(), op2.into(), op3.into()));
self
}
pub fn tge(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tge(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn te(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Te(op1.into(), op2.into(), op3.into()));
self
}
pub fn tne(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tne(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn tl(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Tl(op1.into(), op2.into(), op3.into()));
self
}
pub fn tle(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tle(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn tug(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tug(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn tuge(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tuge(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn tul(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tul(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn tule(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Tule(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn ifs(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(
self.basic_block,
Op::Ifs(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn js(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Js(op1.into(), op2.into(), op3.into()));
self
}
pub fn jmp(&mut self, op1: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Jmp(op1.into()));
self
}
pub fn vexit(&mut self, op1: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Vexit(op1.into()));
self
}
pub fn vxcall(&mut self, op1: Operand) -> &mut Self {
insert_instr(self.basic_block, Op::Vxcall(op1.into()));
self
}
pub fn nop(&mut self) -> &mut Self {
insert_instr(self.basic_block, Op::Nop);
self
}
pub fn sfence(&mut self) -> &mut Self {
insert_instr(self.basic_block, Op::Sfence);
self
}
pub fn lfence(&mut self) -> &mut Self {
insert_instr(self.basic_block, Op::Lfence);
self
}
pub fn vemit(&mut self, op1: ImmediateDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Vemit(op1.into()));
self
}
pub fn vpinr(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Vpinr(op1.into()));
self
}
pub fn vpinw(&mut self, op1: RegisterDesc) -> &mut Self {
insert_instr(self.basic_block, Op::Vpinw(op1.into()));
self
}
pub fn vpinrm(
&mut self,
op1: RegisterDesc,
op2: ImmediateDesc,
op3: ImmediateDesc,
) -> &mut Self {
insert_instr(
self.basic_block,
Op::Vpinrm(op1.into(), op2.into(), op3.into()),
);
self
}
pub fn vpinwm(
&mut self,
op1: RegisterDesc,
op2: ImmediateDesc,
op3: ImmediateDesc,
) -> &mut Self {
insert_instr(
self.basic_block,
Op::Vpinwm(op1.into(), op2.into(), op3.into()),
);
self
}
}
#[cfg(test)]
mod test {
#[test]
fn basic() {
use crate::*;
let mut routine = Routine::new(ArchitectureIdentifier::Virtual);
let basic_block = routine.create_block(Vip(0)).unwrap();
let tmp0 = basic_block.tmp(64);
let mut builder = InstructionBuilder::from(basic_block);
builder.mov(tmp0, 0xA57E6F0335298D0u64.into());
assert_eq!(basic_block.instructions.len(), 1);
let instr = &basic_block.instructions[0];
assert!(matches!(instr.op, Op::Mov(_, _)));
}
}