chore(interpreter): rewrite displacement memoryindex logic
Previously, the displacement for a MemoryIndex was directly interpreted and saved as a signed value. Change this to the normal unsigned ImmediateOperand version to allow for more flexible usage of this struct for general memoryaccess (future commit) and just interpret the displacement member as signed, only when being interpreted as such (memory access, display, ....
This commit is contained in:
140
src/operands.rs
140
src/operands.rs
@@ -189,31 +189,6 @@ impl Add for ImmediateOperand {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Displacement> 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<Byte> 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<ImmediateOperand> 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<ImmediateOperandSigned> 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<Register>,
|
||||
pub index: Option<Register>,
|
||||
pub displacement: Option<Displacement>,
|
||||
pub displacement: Option<ImmediateOperand>,
|
||||
}
|
||||
|
||||
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<ModRmTarget> 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"
|
||||
|
||||
Reference in New Issue
Block a user