From f2f0a8eb4795342a985c49d66eeda73d059e6033 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Mon, 27 Feb 2023 20:22:32 +0100 Subject: Initial support for immediate operands --- src/imm.rs | 35 ++++++++++++++++++++++++++ src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/imm.rs diff --git a/src/imm.rs b/src/imm.rs new file mode 100644 index 0000000..bcf0d31 --- /dev/null +++ b/src/imm.rs @@ -0,0 +1,35 @@ +/// Trait to interact with immediate operands. +pub(crate) trait Imm { + /// Get immediate operand as slice of bytes. + fn bytes(&self) -> &[u8]; +} + +macro_rules! impl_imm { + ($name:ident, $size:expr, from: $( $from:ty ),* $(,)?) => { + /// Immediate operand. + pub struct $name([u8; $size]); + + impl Imm for $name { + /// Get immediate operand as slice of bytes. + fn bytes(&self) -> &[u8] { + &self.0 + } + } + + $( + impl From<$from> for $name { + fn from(imm: $from) -> Self { + let mut buf = [0u8; $size]; + let imm = imm.to_ne_bytes(); + buf[0..imm.len()].copy_from_slice(&imm); + $name(buf) + } + } + )* + } +} + +impl_imm!(Imm8, 1, from: u8, i8); +impl_imm!(Imm16, 2, from: u16, i16, u8, i8); +impl_imm!(Imm32, 4, from: u32, i32, u16, i16, u8, i8); +impl_imm!(Imm64, 8, from: u64, i64, u32, i32, u16, i16, u8, i8); diff --git a/src/lib.rs b/src/lib.rs index 7c24704..35f7919 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ +mod imm; mod insn; mod reg; +use imm::Imm; +pub use imm::{Imm16, Imm32, Imm64, Imm8}; use reg::Reg; pub use reg::{Reg16, Reg32, Reg64, Reg8}; @@ -92,6 +95,40 @@ impl Asm { self.emit(&[opc, modrm]); } + fn encode_oi(&mut self, opc: u8, op1: T, op2: U) + where + Self: EncodeRI, + { + let opc = opc + (op1.idx() & 0b111); + let prefix = >::legacy_prefix(); + let rex = >::rex(op1); + + self.emit_optional(&[prefix, rex]); + self.emit(&[opc]); + self.emit(&op2.bytes()); + } + + fn encode_ri(&mut self, opc: u8, opc_ext: u8, op1: T, op2: U) + where + Self: EncodeRI, + { + // MI operand encoding. + // op1 -> modrm.rm + // op2 -> modrm.reg + let modrm = modrm( + 0b11, /* mod */ + opc_ext, /* reg */ + op1.idx(), /* rm */ + ); + + let prefix = >::legacy_prefix(); + let rex = >::rex(op1); + + self.emit_optional(&[prefix, rex]); + self.emit(&[opc, modrm]); + self.emit(&op2.bytes()); + } + fn encode_mr(&mut self, opc: u8, op1: MemOp, op2: T) where Self: EncodeMR, @@ -161,6 +198,29 @@ impl EncodeRR for Asm { } impl EncodeRR for Asm {} +trait EncodeRI { + fn legacy_prefix() -> Option { + None + } + + fn rex(op1: T) -> Option { + if op1.need_rex() { + Some(rex(op1.rexw(), 0, 0, op1.idx())) + } else { + None + } + } +} + +impl EncodeRI for Asm {} +impl EncodeRI for Asm {} +impl EncodeRI for Asm { + fn legacy_prefix() -> Option { + Some(0x66) + } +} +impl EncodeRI for Asm {} + trait EncodeMR { fn legacy_prefix() -> Option { None @@ -227,3 +287,27 @@ impl Mov for Asm { self.encode_rm(0x8b, op1, op2); } } + +impl Mov for Asm { + fn mov(&mut self, op1: Reg64, op2: Imm64) { + self.encode_oi(0xb8, op1, op2); + } +} + +impl Mov for Asm { + fn mov(&mut self, op1: Reg32, op2: Imm32) { + self.encode_oi(0xb8, op1, op2); + } +} + +impl Mov for Asm { + fn mov(&mut self, op1: Reg16, op2: Imm16) { + self.encode_oi(0xb8, op1, op2); + } +} + +impl Mov for Asm { + fn mov(&mut self, op1: Reg8, op2: Imm8) { + self.encode_oi(0xb0, op1, op2); + } +} -- cgit v1.2.3