aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-11-29 16:50:18 -0800
committeriximeow <me@iximeow.net>2020-01-12 16:10:13 -0800
commit5c86aaf06d0f638d3fc1d302ef4d401b0222bee1 (patch)
treecac7d1294fca70707ea6fac3ff472fe93796edca
parent324c58fee142e0ea987d1d23a7e25142dde803d0 (diff)
support imul, >2 operands, and 4-bit register bank
-rw-r--r--src/display.rs113
-rw-r--r--src/lib.rs33
-rw-r--r--test/test.rs4
3 files changed, 91 insertions, 59 deletions
diff --git a/src/display.rs b/src/display.rs
index 0694265..1c5792e 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -706,75 +706,78 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi
x.colorize(colors, out)?;
}
};
- match self.opcode {
- Opcode::MOVSX_b |
- Opcode::MOVZX_b => {
- match context.and_then(|xs| xs[1].as_ref()) {
- Some(s) => { write!(out, ", {}", s) }
- None => {
- match &self.operands[1] {
- &OperandSpec::Nothing => {
- unreachable!();
- },
- &OperandSpec::RegMMM => {
- write!(out, ", ")?;
- }
- x @ _ => {
- write!(out, ", byte ")?;
- if let Some(prefix) = self.segment_override_for_op(1) {
- write!(out, "{}:", prefix)?;
+ for i in 1..4 {
+ match self.opcode {
+ Opcode::MOVSX_b |
+ Opcode::MOVZX_b => {
+ match context.and_then(|xs| xs[i].as_ref()) {
+ Some(s) => { write!(out, ", {}", s)? }
+ None => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ &OperandSpec::RegMMM => {
+ write!(out, ", ")?;
+ }
+ x @ _ => {
+ write!(out, ", byte ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
}
}
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
}
- let x = Operand::from_spec(self, self.operands[1]);
- x.colorize(colors, out)
}
- }
- },
- Opcode::MOVSX_w |
- Opcode::MOVZX_w => {
- match context.and_then(|xs| xs[1].as_ref()) {
- Some(s) => { write!(out, ", {}", s) }
- None => {
- match &self.operands[1] {
- &OperandSpec::Nothing => {
- unreachable!();
- },
- &OperandSpec::RegMMM => {
- write!(out, ", ")?;
- }
- _ => {
- write!(out, ", word ")?;
- if let Some(prefix) = self.segment_override_for_op(1) {
- write!(out, "{}:", prefix)?;
+ },
+ Opcode::MOVSX_w |
+ Opcode::MOVZX_w => {
+ match context.and_then(|xs| xs[i].as_ref()) {
+ Some(s) => { write!(out, ", {}", s)? }
+ None => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ &OperandSpec::RegMMM => {
+ write!(out, ", ")?;
+ }
+ _ => {
+ write!(out, ", word ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
}
}
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
}
- let x = Operand::from_spec(self, self.operands[1]);
- x.colorize(colors, out)
}
- }
- },
- _ => {
- match context.and_then(|xs| xs[1].as_ref()) {
- Some(s) => { write!(out, ", {}", s) }
- None => {
- match &self.operands[1] {
- &OperandSpec::Nothing => {
- return Ok(());
- },
- _ => {
- write!(out, ", ")?;
- if let Some(prefix) = self.segment_override_for_op(1) {
- write!(out, "{}:", prefix)?;
+ },
+ _ => {
+ match context.and_then(|xs| xs[i].as_ref()) {
+ Some(s) => { write!(out, ", {}", s)? }
+ None => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ _ => {
+ write!(out, ", ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
}
- let x = Operand::from_spec(self, self.operands[1]);
- x.colorize(colors, out)
}
}
}
}
}
}
+ Ok(())
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 705966c..d507f3c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1522,7 +1522,6 @@ fn read_opcode_f20f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u
Some(record)
}
None => {
- unsafe { unreachable_unchecked(); }
None
}
}
@@ -1810,7 +1809,6 @@ fn read_opcode_f30f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u
Some(record)
}
None => {
- unsafe { unreachable_unchecked(); }
None
}
}
@@ -2139,7 +2137,6 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u8)
Some(record)
}
None => {
- unsafe { unreachable_unchecked(); }
None
}
}
@@ -2806,7 +2803,11 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
}
} else {
opwidth = 1;
- bank = RegisterBank::B;
+ if instruction.prefixes.rex().present() {
+ bank = RegisterBank::rB;
+ } else {
+ bank = RegisterBank::B;
+ }
};
modrm = read_modrm(&mut bytes_iter, instruction, length)?;
instruction.modrm_rrr =
@@ -3017,6 +3018,7 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
instruction.imm = read_imm_signed(&mut bytes_iter, numwidth, length)? as u64;
bytes_read = numwidth;
instruction.operands[1] = match opwidth {
+ 1 => OperandSpec::ImmI8,
2 => OperandSpec::ImmI16,
4 => OperandSpec::ImmI32,
8 => OperandSpec::ImmI64,
@@ -3192,6 +3194,29 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
instruction.operand_count = 1;
instruction.operands[0] = OperandSpec::ImmI32;
}
+ OperandCode::Gb_Eb_Ib => {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, 1, length)? as u64;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ }
+ OperandCode::Gv_Ev_Iv => {
+ let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ let numwidth = if opwidth == 8 { 4 } else { opwidth };
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, numwidth, length)? as u64;
+ instruction.operands[2] = match opwidth {
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ 8 => OperandSpec::ImmI64,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 3;
+ }
OperandCode::Nothing => {
instruction.operand_count = 0;
}
diff --git a/test/test.rs b/test/test.rs
index 3182503..b88e470 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -88,6 +88,9 @@ fn test_system() {
fn test_arithmetic() {
test_display(&[0x81, 0xec, 0x10, 0x03, 0x00, 0x00], "sub esp, 0x310");
test_display(&[0x0f, 0xaf, 0xc2], "imul eax, edx");
+ test_display(&[0x4b, 0x69, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65], "imul rax, [r11 + 0x6f], 0x656c706d");
+ test_display(&[0x4b, 0x6b, 0x43, 0x6f, 0x6d], "imul al, [r11 + 0x6f], 0x6d");
+ test_display(&[0x4f, 0x4e, 0x00, 0xcc], "add spl, r9b");
}
#[test]
@@ -188,6 +191,7 @@ fn test_control_flow() {
#[test]
fn test_test_cmp() {
+ test_display(&[0xf6, 0x05, 0x2c, 0x9b, 0xff, 0xff, 0x01], "test [rip - 0x64d4], 0x1");
test_display(&[0x48, 0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp rax, -0xfff");
test_display(&[0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp eax, -0xfff");
test_display(&[0x48, 0x83, 0xf8, 0xff], "cmp rax, -0x1");