mod insn; mod reg; use reg::Reg; pub use reg::{Reg16, Reg32, Reg64, Reg8}; use insn::Mov; pub enum MemOp { Indirect(Reg64), IndirectDisp(Reg64, i32), } impl MemOp { const fn base(&self) -> Reg64 { match self { MemOp::Indirect(base) => *base, MemOp::IndirectDisp(base, ..) => *base, } } } /// Encode the `REX` byte. const fn rex(w: u8, r: u8, x: u8, b: u8) -> u8 { let r = (r >> 3) & 1; let x = (x >> 3) & 1; let b = (b >> 3) & 1; 0b0100_0000 | ((w & 1) << 3) | (r << 2) | (x << 1) | b } /// Encode the `ModR/M` byte. const fn modrm(mod_: u8, reg: u8, rm: u8) -> u8 { ((mod_ & 0b11) << 6) | ((reg & 0b111) << 3) | (rm & 0b111) } pub struct Asm { buf: Vec, } impl Asm { pub fn new() -> Asm { let buf = Vec::with_capacity(1024); Asm { buf } } pub fn into_code(self) -> Vec { self.buf } fn emit(&mut self, bytes: &[u8]) { self.buf.extend_from_slice(bytes); } fn emit_optional(&mut self, bytes: &[Option]) { for byte in bytes.iter().filter_map(|&b| b) { self.buf.push(byte); } } fn emit_at(&mut self, pos: usize, bytes: &[u8]) { if let Some(buf) = self.buf.get_mut(pos..pos + bytes.len()) { buf.copy_from_slice(bytes); } else { unimplemented!(); } } pub fn mov(&mut self, op1: T, op2: U) where Self: Mov, { >::mov(self, op1, op2); } fn encode_rr(&mut self, opc: u8, op1: T, op2: T) where Self: EncodeRR, { // MR operand encoding. // op1 -> modrm.rm // op2 -> modrm.reg let modrm = modrm( 0b11, /* mod */ op2.idx(), /* reg */ op1.idx(), /* rm */ ); let prefix = >::legacy_prefix(); let rex = >::rex(op1, op2); self.emit_optional(&[prefix, rex]); self.emit(&[opc, modrm]); } fn encode_mr(&mut self, opc: u8, op1: MemOp, op2: T) where Self: EncodeMR, { // MR operand encoding. // op1 -> modrm.rm // op2 -> modrm.reg let mode = match op1 { MemOp::Indirect(..) => { assert!(!op1.base().need_sib() && !op1.base().is_pc_rel()); 0b00 } MemOp::IndirectDisp(..) => { assert!(!op1.base().need_sib()); 0b10 } }; let modrm = modrm( mode, /* mode */ op2.idx(), /* reg */ op1.base().idx(), /* rm */ ); let prefix = >::legacy_prefix(); let rex = >::rex(&op1, op2); self.emit_optional(&[prefix, rex]); self.emit(&[opc, modrm]); if let MemOp::IndirectDisp(_, disp) = op1 { self.emit(&disp.to_ne_bytes()); } } fn encode_rm(&mut self, opc: u8, op1: T, op2: MemOp) where Self: EncodeMR, { // RM operand encoding. // op1 -> modrm.reg // op2 -> modrm.rm self.encode_mr(opc, op2, op1); } } // -- Encoder helper. trait EncodeRR { fn legacy_prefix() -> Option { None } fn rex(op1: T, op2: T) -> Option { if op1.need_rex() || op2.need_rex() { Some(rex(op1.rexw(), op2.idx(), 0, op1.idx())) } else { None } } } impl EncodeRR for Asm {} impl EncodeRR for Asm {} impl EncodeRR for Asm { fn legacy_prefix() -> Option { Some(0x66) } } impl EncodeRR for Asm {} trait EncodeMR { fn legacy_prefix() -> Option { None } fn rex(op1: &MemOp, op2: T) -> Option { if op1.base().need_rex() || op2.need_rex() { Some(rex(op2.rexw(), op2.idx(), 0, op1.base().idx())) } else { None } } } impl EncodeMR for Asm {} impl EncodeMR for Asm {} // -- Instruction implementations. impl Mov for Asm { fn mov(&mut self, op1: Reg64, op2: Reg64) { self.encode_rr(0x89, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: Reg32, op2: Reg32) { self.encode_rr(0x89, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: Reg16, op2: Reg16) { self.encode_rr(0x89, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: Reg8, op2: Reg8) { self.encode_rr(0x88, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: MemOp, op2: Reg64) { self.encode_mr(0x89, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: MemOp, op2: Reg32) { self.encode_mr(0x89, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: Reg64, op2: MemOp) { self.encode_rm(0x8b, op1, op2); } } impl Mov for Asm { fn mov(&mut self, op1: Reg32, op2: MemOp) { self.encode_rm(0x8b, op1, op2); } }