ft: abstract and implement ADD::* interpretation
This commit is contained in:
@@ -7,6 +7,7 @@ use crate::register::SegmentRegister;
|
||||
|
||||
use crate::{disasm::DisasmError, register::Register};
|
||||
use core::fmt;
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
pub type Byte = u8; // b
|
||||
pub type IByte = i8; // used for displacements of memory access
|
||||
@@ -14,7 +15,7 @@ pub type Word = u16; // w or v
|
||||
pub type IWord = i16; // used for displacement of memory access
|
||||
pub type DWord = u32;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd, Copy)]
|
||||
/// 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
|
||||
@@ -24,6 +25,64 @@ pub enum Operand {
|
||||
Word(Word),
|
||||
}
|
||||
|
||||
impl Add for Operand {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
match self {
|
||||
Operand::Byte(lhsb) => match other {
|
||||
Operand::Byte(rhsb) => Operand::Byte(lhsb.wrapping_add(rhsb)),
|
||||
_ => panic!("Cannot add Word to Byte"),
|
||||
},
|
||||
Operand::Word(lhsw) => match other {
|
||||
Operand::Word(rhsw) => Operand::Word(lhsw.wrapping_add(rhsw)),
|
||||
Operand::Byte(rhsb) => Operand::Word(lhsw.wrapping_add(rhsb as Word)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Displacement> for Operand {
|
||||
type Output = Operand;
|
||||
|
||||
fn add(self, disp: Displacement) -> Self::Output {
|
||||
// XXX: ugly hack to add Operand with Displacement
|
||||
match disp {
|
||||
Displacement::IByte(byte) => {
|
||||
if byte < 0 {
|
||||
return self - Operand::Byte((byte * -1) as Byte);
|
||||
} else {
|
||||
return self + Operand::Byte(byte as Byte);
|
||||
}
|
||||
}
|
||||
Displacement::IWord(word) => {
|
||||
if word < 0 {
|
||||
return self - Operand::Word((word * -1) as Word);
|
||||
} else {
|
||||
return self + Operand::Word(word as Word);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Operand {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self {
|
||||
match self {
|
||||
Operand::Byte(lhsb) => match other {
|
||||
Operand::Byte(rhsb) => Operand::Byte(lhsb.wrapping_sub(rhsb)),
|
||||
_ => panic!("Cannot substract Word from Byte"),
|
||||
},
|
||||
Operand::Word(lhsw) => match other {
|
||||
Operand::Word(rhsw) => Operand::Word(lhsw.wrapping_sub(rhsw)),
|
||||
Operand::Byte(rhsb) => Operand::Word(lhsw.wrapping_sub(rhsb as Word)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Operand {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -42,7 +101,7 @@ impl fmt::LowerHex for Operand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
/// ModRM byte can either target a [`MemoryIndex`] (location in memory) or some
|
||||
/// [`Register`].
|
||||
pub enum ModRmTarget {
|
||||
@@ -59,7 +118,7 @@ impl std::fmt::Display for ModRmTarget {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
/// Memory displacements are 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
|
||||
@@ -105,7 +164,7 @@ impl std::fmt::Display for Displacement {
|
||||
|
||||
/// A memory index operand is usually created by ModRM bytes or words.
|
||||
/// e.g. [bx+si]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
pub struct MemoryIndex {
|
||||
pub base: Option<Register>,
|
||||
pub index: Option<Register>,
|
||||
@@ -141,7 +200,7 @@ impl fmt::Display for MemoryIndex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
/// 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
|
||||
@@ -185,7 +244,7 @@ impl TryFrom<ModRmTarget> for Pointer16 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
/// 32-bit segment:offset pointer for long jumps.
|
||||
/// Both [`Word`]s are immediately encoded after the instruction
|
||||
pub struct Pointer32 {
|
||||
|
||||
Reference in New Issue
Block a user