From 3f47ede3d0a1aaf3a9176ab9c93b8d0e970388f2 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Tue, 5 Dec 2023 00:56:58 +0100 Subject: insn: add additional insn required for the new tiny_vm example --- src/insn.rs | 6 ++++++ src/insn/add.rs | 12 ++++++++++++ src/insn/cmp.rs | 7 +++++++ src/insn/mov.rs | 8 ++++++++ src/insn/test.rs | 6 ++++++ src/lib.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/prelude.rs | 2 +- 7 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/insn/cmp.rs (limited to 'src') diff --git a/src/insn.rs b/src/insn.rs index 8810085..11405c1 100644 --- a/src/insn.rs +++ b/src/insn.rs @@ -2,6 +2,7 @@ mod add; mod call; +mod cmp; mod dec; mod jmp; mod jnz; @@ -21,6 +22,11 @@ pub trait Call { fn call(&mut self, op1: T); } +pub trait Cmp { + /// Emit a compare call instruction. + fn cmp(&mut self, op1: T, op2: U); +} + pub trait Dec { /// Emit a decrement instruction. fn dec(&mut self, op1: T); diff --git a/src/insn/add.rs b/src/insn/add.rs index 3757d14..8232fe4 100644 --- a/src/insn/add.rs +++ b/src/insn/add.rs @@ -11,3 +11,15 @@ impl Add for Asm { self.encode_rr(0x01, op1, op2); } } + +impl Add for Asm { + fn add(&mut self, op1: MemOp, op2: Reg16) { + self.encode_mr(0x01, op1, op2); + } +} + +impl Add for Asm { + fn add(&mut self, op1: MemOp, op2: Imm16) { + self.encode_mi(0x81, 0, op1, op2); + } +} diff --git a/src/insn/cmp.rs b/src/insn/cmp.rs new file mode 100644 index 0000000..93aa26c --- /dev/null +++ b/src/insn/cmp.rs @@ -0,0 +1,7 @@ +use crate::prelude::*; + +impl Cmp for Asm { + fn cmp(&mut self, op1: MemOp, op2: Imm16) { + self.encode_mi(0x81, 0x7, op1, op2); + } +} diff --git a/src/insn/mov.rs b/src/insn/mov.rs index bf1c33e..2614d82 100644 --- a/src/insn/mov.rs +++ b/src/insn/mov.rs @@ -103,3 +103,11 @@ impl Mov for Asm { self.encode_oi(0xb0, op1, op2); } } + +// -- MOV : mem imm + +impl Mov for Asm { + fn mov(&mut self, op1: MemOp, op2: Imm16) { + self.encode_mi(0xc7, 0, op1, op2); + } +} diff --git a/src/insn/test.rs b/src/insn/test.rs index 25f1680..b7ac774 100644 --- a/src/insn/test.rs +++ b/src/insn/test.rs @@ -11,3 +11,9 @@ impl Test for Asm { self.encode_rr(0x85, op1, op2); } } + +impl Test for Asm { + fn test(&mut self, op1: MemOp, op2: Imm16) { + self.encode_mi(0xf7, 0, op1, op2); + } +} diff --git a/src/lib.rs b/src/lib.rs index 0cc86fb..8348435 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -273,6 +273,42 @@ impl Asm { self.emit(&[opc, modrm]); } + /// Encode a memory-immediate instruction. + fn encode_mi(&mut self, opc: u8, opc_ext: u8, op1: MemOp, op2: T) + where + Self: EncodeMI, + { + // MI operand encoding. + // op1 -> modrm.rm + // op2 -> imm + 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 */ + opc_ext, /* reg */ + op1.base().idx(), /* rm */ + ); + + let prefix = >::legacy_prefix(); + let rex = >::rex(&op1); + + self.emit_optional(&[prefix, rex]); + self.emit(&[opc, modrm]); + if let MemOp::IndirectDisp(_, disp) = op1 { + self.emit(&disp.to_ne_bytes()); + } + self.emit(op2.bytes()); + } + /// Encode a memory-register instruction. fn encode_mr(&mut self, opc: u8, op1: MemOp, op2: T) where @@ -408,3 +444,26 @@ impl EncodeMR for Asm { } impl EncodeMR for Asm {} impl EncodeMR for Asm {} + +/// Encode helper for memory-immediate instructions. +trait EncodeMI { + fn legacy_prefix() -> Option { + None + } + + fn rex(op1: &MemOp) -> Option { + if op1.base().is_ext() { + Some(rex(false, 0, 0, op1.base().idx())) + } else { + None + } + } +} + +impl EncodeMI for Asm {} +impl EncodeMI for Asm { + fn legacy_prefix() -> Option { + Some(0x66) + } +} +impl EncodeMI for Asm {} diff --git a/src/prelude.rs b/src/prelude.rs index b21d67c..d8dd912 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,4 +7,4 @@ pub use crate::imm::{Imm16, Imm32, Imm64, Imm8}; pub use crate::label::Label; pub use crate::reg::{Reg16, Reg32, Reg64, Reg8}; -pub use crate::insn::{Add, Call, Dec, Jmp, Jnz, Jz, Mov, Test}; +pub use crate::insn::{Add, Call, Cmp, Dec, Jmp, Jnz, Jz, Mov, Test}; -- cgit v1.2.3