diff --git a/src/disasm.rs b/src/disasm.rs index 01f2ff6..d716ec5 100644 --- a/src/disasm.rs +++ b/src/disasm.rs @@ -2,8 +2,8 @@ use crate::aout::Aout; use crate::operands::{ - Byte, DWord, Displacement, IByte, IWord, ImmediateOperand, MemoryIndex, ModRmTarget, Pointer16, - Pointer32, Word, + Byte, DWord, IByte, IWord, ImmediateOperand, MemoryIndex, ModRmTarget, Pointer16, Pointer32, + Word, }; use crate::register::{Register, RegisterId, SegmentRegister}; use crate::{ @@ -269,7 +269,7 @@ impl Disassembler { match mode { 0b00 => { if rm == 0b110 { - let word = Displacement::IWord(self.parse_word()? as IWord); + let word = ImmediateOperand::Word(self.parse_word()?); log::debug!("ModRM direct memory read at {word:?}"); displacement = Some(word); return Ok(( @@ -286,12 +286,12 @@ impl Disassembler { } } 0b01 => { - let byte = Displacement::IByte(self.parse_byte()? as IByte); + let byte = ImmediateOperand::Byte(self.parse_byte()?); log::debug!("ModRM has a single byte of displacement: {byte}."); displacement = Some(byte); } 0b10 => { - let word = Displacement::IWord(self.parse_word()? as IWord); + let word = ImmediateOperand::Word(self.parse_word()?); log::debug!("ModRM has a single word of displacement: {word}"); displacement = Some(word); } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 879d114..a8d79e3 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -631,6 +631,34 @@ impl Interpreter { /* * Load ES/DS Register */ + Mnemonic::LES(reg, ptr) => { + let offset = self + .computer + .memory + .read_raw(self.computer.sregs.ds * 16 + ptr.word)?; + let segment = self + .computer + .memory + .read_raw(self.computer.sregs.ds * 16 + ptr.word + 2)?; + self.computer.sregs.es = segment; + self.computer + .regs + .write(reg, ImmediateOperand::from(offset)); + } + Mnemonic::LDS(reg, ptr) => { + let offset = self + .computer + .memory + .read_raw(self.computer.sregs.ds * 16 + ptr.word)?; + let segment = self + .computer + .memory + .read_raw(self.computer.sregs.ds * 16 + ptr.word + 2)?; + self.computer.sregs.ds = segment; + self.computer + .regs + .write(reg, ImmediateOperand::from(offset)); + } /* * Not/Neg diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index b98ca12..8346f1c 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -1,4 +1,4 @@ -use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word}; +use crate::operands::{Byte, ImmediateOperand, ImmediateOperandSigned, MemoryIndex, Word}; use super::interpreter::InterpreterError; use crate::interpreter::register::{Register, SegmentRegister}; @@ -97,7 +97,7 @@ impl Memory { ) -> Word { let mut base = ImmediateOperand::Word(0); let mut index = ImmediateOperand::Word(0); - let mut disp = Displacement::IWord(0); + let mut disp = ImmediateOperandSigned::Word(0); if let Some(base_reg) = idx.base { base = regs.read(base_reg); @@ -106,7 +106,7 @@ impl Memory { index = regs.read(index_reg); }; if let Some(displacement) = idx.displacement { - disp = displacement; + disp = ImmediateOperandSigned::from(displacement); } Self::addr_offset((base + index + disp).into(), sregs) diff --git a/src/interpreter/register.rs b/src/interpreter/register.rs index e60fc43..cdc3d49 100644 --- a/src/interpreter/register.rs +++ b/src/interpreter/register.rs @@ -165,10 +165,10 @@ gen_regs!(DX); #[derive(Debug, Clone, Copy)] pub struct SegmentRegister { - pub ds: Word, - pub es: Word, - pub ss: Word, - pub cs: Word, + pub ds: Word, // data segment + pub es: Word, // extra segment + pub ss: Word, // stack segment + pub cs: Word, // code segment } impl SegmentRegister { diff --git a/src/operands.rs b/src/operands.rs index c2bbf92..fcb34e4 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -189,31 +189,6 @@ impl Add for ImmediateOperand { } } -impl Add for ImmediateOperand { - type Output = ImmediateOperand; - - fn add(self, disp: Displacement) -> Self::Output { - // Warning: this gets rid of the sign, which is fine as long as it is - // used for a memory index, which can never be negative. - match disp { - Displacement::IByte(byte) => { - if byte < 0 { - return self - ImmediateOperand::Byte((byte * -1) as Byte); - } else { - return self + ImmediateOperand::Byte(byte as Byte); - } - } - Displacement::IWord(word) => { - if word < 0 { - return self - ImmediateOperand::Word((word * -1) as Word); - } else { - return self + ImmediateOperand::Word(word as Word); - } - } - } - } -} - impl Add for ImmediateOperand { type Output = ImmediateOperand; @@ -475,39 +450,42 @@ impl std::fmt::Display for ModRmTarget { } #[derive(Debug, Clone, PartialEq, Eq, Copy)] -/// Memory displacements are concrete signed versions of Byte and Word operands. -/// Encodes either Byte- or Word-sized operands. -/// Generally, a [`Displacement`] is the result of a ModRM byte parse and -/// usually really is the signed displacement of a [`MemoryIndex`] for memory -/// operations. -/// Although, some instructions use this parsed displacement as an unsigned -/// pointer, hence the [`Displacement`] will be cast to [`Pointer16`], when this -/// is the case. -pub enum Displacement { - IByte(IByte), - IWord(IWord), +/// Just a wrapper to access QOL function, which interprets an +/// [`ImmediateOperand`] as a signed value. +pub enum ImmediateOperandSigned { + Byte(IByte), + Word(IWord), } -impl fmt::LowerHex for Displacement { +impl fmt::LowerHex for ImmediateOperandSigned { 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), + Self::Byte(b) => fmt::LowerHex::fmt(b, f), + Self::Word(v) => fmt::LowerHex::fmt(v, f), } } } -impl std::fmt::Display for Displacement { +impl From for ImmediateOperandSigned { + fn from(value: ImmediateOperand) -> Self { + match value { + ImmediateOperand::Byte(b) => Self::Byte(b as IByte), + ImmediateOperand::Word(w) => Self::Word(w as IWord), + } + } +} + +impl std::fmt::Display for ImmediateOperandSigned { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::IByte(b) => { + Self::Byte(b) => { if *b > 0 { write!(f, " + {:#x}", b) } else { write!(f, " - {:#x}", b * -1) } } - Self::IWord(w) => { + Self::Word(w) => { if *w > 0 { write!(f, " + {:#x}", w) } else { @@ -518,13 +496,57 @@ impl std::fmt::Display for Displacement { } } +impl Add for ImmediateOperand { + type Output = ImmediateOperand; + fn add(self, disp: ImmediateOperandSigned) -> Self::Output { + // Warning: this gets rid of the sign, which is fine as long as it is + // used for a memory index, which can never be negative. + // In that case, the subtract wraps. + match disp { + ImmediateOperandSigned::Byte(byte) => { + if byte < 0 { + return self - ImmediateOperand::Byte((byte * -1) as Byte); + } else { + return self + ImmediateOperand::Byte(byte as Byte); + } + } + ImmediateOperandSigned::Word(word) => { + if word < 0 { + return self - ImmediateOperand::Word((word * -1) as Word); + } else { + return self + ImmediateOperand::Word(word as Word); + } + } + } + } +} /// A memory index operand is usually created by ModRM bytes or words. /// e.g. [bx+si] #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub struct MemoryIndex { pub base: Option, pub index: Option, - pub displacement: Option, + pub displacement: Option, +} + +impl MemoryIndex { + /// Creates a [`MemoryIndex`] with just a single [`Register`] + pub fn reg(reg: Register) -> Self { + Self { + base: Some(reg), + index: None, + displacement: None, + } + } + + /// Creates a [`MemoryIndex`] with an [`ImmediateOperand`] + pub fn disp(disp: ImmediateOperand) -> Self { + Self { + base: None, + index: None, + displacement: Some(disp), + } + } } impl fmt::Display for MemoryIndex { @@ -533,22 +555,42 @@ impl fmt::Display for MemoryIndex { Some(base) => match &self.index { Some(index) => match &self.displacement { Some(displacement) => { - write!(f, "[{} + {}{}]", base, index, displacement) + write!( + f, + "[{} + {}{}]", + base, + index, + ImmediateOperandSigned::from(displacement.clone().to_owned()) + ) } None => write!(f, "[{} + {}]", base, index), }, None => match &self.displacement { - Some(displacement) => write!(f, "[{}{}]", base, displacement), + Some(displacement) => write!( + f, + "[{}{}]", + base, + ImmediateOperandSigned::from(displacement.clone().to_owned()) + ), None => write!(f, "[{}]", base), }, }, None => match &self.index { Some(index) => match &self.displacement { - Some(displacement) => write!(f, "[{}{}]", index, displacement), + Some(displacement) => write!( + f, + "[{}{}]", + index, + ImmediateOperandSigned::from(displacement.clone().to_owned()) + ), None => write!(f, "[{}]", index), }, None => match &self.displacement { - Some(displacement) => write!(f, "[{:#x}]", displacement), + Some(displacement) => write!( + f, + "[{:#x}]", + ImmediateOperandSigned::from(displacement.clone().to_owned()) + ), None => panic!("Memory Index without base, index and displacement"), }, }, @@ -560,7 +602,7 @@ impl fmt::Display for MemoryIndex { /// 16-bit pointer for access, usually with a [`SegmentRegister`] as segment /// and [`Pointer16`] as offset. /// Generally, this type only gets constructed in rare scenarios, when the -/// [`Displacement`] of ModRM byte is used as a raw pointer. +/// [`Displacement`] of a parsed [`ModRmTarget`] is used as a raw pointer. pub struct Pointer16 { pub word: Word, } @@ -578,7 +620,7 @@ impl TryFrom for Pointer16 { match target { ModRmTarget::Memory(mem) => match mem.displacement { Some(disp) => match disp { - Displacement::IWord(word) => Ok(Pointer16 { word: word as Word }), + ImmediateOperand::Word(word) => Ok(Pointer16 { word }), _ => { return Err(DisasmError::IllegalOperand( "Tried to construct Pointer16 with Byte, when a Word is expected"