//! All types which a Mnemonic can have as some kind of operand. //! This includes things such as immediates, ModRM byte targets, etc. etc. use crate::register::Register; use core::fmt; pub type Byte = u8; // b pub type IByte = i8; // used for displacements of memory access pub type Word = u16; // w or v pub type IWord = i16; // used for displacement of memory access pub type DWord = u32; #[derive(Debug, Clone)] /// Encodes either Byte- or Word-sized operands. /// Also sometimes used to decide if an instruction is Byte- or Word-sized, /// which is usually indicated by using a value of 0 and the disregarding /// the value when read. pub enum Operand { Byte(Byte), Word(Word), } impl fmt::Display for Operand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Byte(byte) => write!(f, "{}", byte), Self::Word(word) => write!(f, "{}", word), } } } impl fmt::LowerHex for Operand { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Byte(b) => fmt::LowerHex::fmt(b, f), Self::Word(v) => fmt::LowerHex::fmt(v, f), } } } #[derive(Debug, Clone, PartialEq, Eq)] /// ModRM byte can either target a memory location or some register. pub enum ModRmTarget { Memory(MemoryIndex), Register(Register), } impl std::fmt::Display for ModRmTarget { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Memory(idx) => write!(f, "{}", idx), Self::Register(reg) => write!(f, "{}", reg), } } } #[derive(Debug, Clone, PartialEq, Eq)] /// Memory displacements are signed versions of Byte and Word operands. /// Encodes either Byte- or Word-sized operands. pub enum Displacement { IByte(IByte), IWord(IWord), } impl fmt::LowerHex for Displacement { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::IByte(b) => fmt::LowerHex::fmt(b, f), Self::IWord(v) => fmt::LowerHex::fmt(v, f), } } } impl std::fmt::Display for Displacement { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::IByte(b) => { if *b > 0 { write!(f, " + {:#x}", b) } else { write!(f, " - {:#x}", b * -1) } } Self::IWord(w) => { if *w > 0 { write!(f, " + {:#x}", w) } else { write!(f, " - {:#x}", w * -1) } } } } } /// A memory index operand is usually created by ModRM bytes or words. /// e.g. [bx+si] #[derive(Debug, Clone, PartialEq, Eq)] pub struct MemoryIndex { pub base: Option, pub index: Option, pub displacement: Option, } impl fmt::Display for MemoryIndex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.base { Some(base) => match &self.index { Some(index) => match &self.displacement { Some(displacement) => { write!(f, "[{} + {}{}]", base, index, displacement) } None => write!(f, "[{} + {}]", base, index), }, None => match &self.displacement { Some(displacement) => write!(f, "[{}{}]", base, displacement), None => write!(f, "[{}]", base), }, }, None => match &self.index { Some(index) => match &self.displacement { Some(displacement) => write!(f, "[{}{}]", index, displacement), None => write!(f, "[{}]", index), }, None => match &self.displacement { Some(displacement) => write!(f, "[{:#x}]", displacement), None => panic!("Memory Index without base, index and displacement"), }, }, } } } #[derive(Debug, Clone, PartialEq, Eq)] /// 32-bit segment:offset pointer (e.g. for CALL instruction) pub struct Pointer { pub raw: DWord, pub segment: Word, pub offset: Word, } impl std::fmt::Display for Pointer { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "[{:#04x}] ({}:{})", self.raw, self.segment, self.offset) } }