aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/insn.rs6
-rw-r--r--src/insn/add.rs12
-rw-r--r--src/insn/cmp.rs7
-rw-r--r--src/insn/mov.rs8
-rw-r--r--src/insn/test.rs6
-rw-r--r--src/lib.rs59
-rw-r--r--src/prelude.rs2
7 files changed, 99 insertions, 1 deletions
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<T> {
fn call(&mut self, op1: T);
}
+pub trait Cmp<T, U> {
+ /// Emit a compare call instruction.
+ fn cmp(&mut self, op1: T, op2: U);
+}
+
pub trait Dec<T> {
/// 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<Reg32, Reg32> for Asm {
self.encode_rr(0x01, op1, op2);
}
}
+
+impl Add<MemOp, Reg16> for Asm {
+ fn add(&mut self, op1: MemOp, op2: Reg16) {
+ self.encode_mr(0x01, op1, op2);
+ }
+}
+
+impl Add<MemOp, Imm16> 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<MemOp, Imm16> 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<Reg8, Imm8> for Asm {
self.encode_oi(0xb0, op1, op2);
}
}
+
+// -- MOV : mem imm
+
+impl Mov<MemOp, Imm16> 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<Reg32, Reg32> for Asm {
self.encode_rr(0x85, op1, op2);
}
}
+
+impl Test<MemOp, Imm16> 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<T: Imm>(&mut self, opc: u8, opc_ext: u8, op1: MemOp, op2: T)
+ where
+ Self: EncodeMI<T>,
+ {
+ // 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 = <Self as EncodeMI<T>>::legacy_prefix();
+ let rex = <Self as EncodeMI<T>>::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<T: Reg>(&mut self, opc: u8, op1: MemOp, op2: T)
where
@@ -408,3 +444,26 @@ impl EncodeMR<Reg16> for Asm {
}
impl EncodeMR<Reg32> for Asm {}
impl EncodeMR<Reg64> for Asm {}
+
+/// Encode helper for memory-immediate instructions.
+trait EncodeMI<T: Imm> {
+ fn legacy_prefix() -> Option<u8> {
+ None
+ }
+
+ fn rex(op1: &MemOp) -> Option<u8> {
+ if op1.base().is_ext() {
+ Some(rex(false, 0, 0, op1.base().idx()))
+ } else {
+ None
+ }
+ }
+}
+
+impl EncodeMI<Imm8> for Asm {}
+impl EncodeMI<Imm16> for Asm {
+ fn legacy_prefix() -> Option<u8> {
+ Some(0x66)
+ }
+}
+impl EncodeMI<Imm32> 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};