aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-06-30 12:56:08 -0700
committeriximeow <me@iximeow.net>2020-01-12 16:10:13 -0800
commit2f9867664191bcfe0b7f7209de7463df30f775de (patch)
tree6f8e5f2265b201ece2712c1db321b09a4db2511d
parent49d2e670b56d43d079775f01a02f31555bb9da73 (diff)
add more x86 instructions (bt, btr, bts, bsf, ...) and xadd
-rw-r--r--src/display.rs26
-rw-r--r--src/lib.rs153
-rw-r--r--test/test.rs8
3 files changed, 182 insertions, 5 deletions
diff --git a/src/display.rs b/src/display.rs
index ca2b2f7..cbf3e61 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -183,6 +183,13 @@ impl <T: std::fmt::Write> Colorize<T> for Operand {
impl fmt::Display for Opcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+ &Opcode::XADD => write!(f, "{}", "xadd"),
+ &Opcode::BT => write!(f, "{}", "bt"),
+ &Opcode::BTS => write!(f, "{}", "bts"),
+ &Opcode::BTR => write!(f, "{}", "btr"),
+ &Opcode::BTC => write!(f, "{}", "btc"),
+ &Opcode::BSF => write!(f, "{}", "bsf"),
+ &Opcode::BSR => write!(f, "{}", "bsr"),
&Opcode::MOVSS => write!(f, "{}", "movss"),
&Opcode::SQRTSS => write!(f, "{}", "sqrtss"),
&Opcode::ADDSS => write!(f, "{}", "addss"),
@@ -350,8 +357,11 @@ impl fmt::Display for Opcode {
&Opcode::DIV => write!(f, "{}", "div"),
&Opcode::IDIV => write!(f, "{}", "idiv"),
&Opcode::CMPXCHG => write!(f, "{}", "cmpxchg"),
+ &Opcode::MOVSX_b => write!(f, "{}", "movsx"),
+ &Opcode::MOVSX_w => write!(f, "{}", "movsx"),
&Opcode::MOVZX_b => write!(f, "{}", "movzx"),
&Opcode::MOVZX_w => write!(f, "{}", "movzx"),
+ &Opcode::MOVSXD => write!(f, "{}", "movsxd"),
&Opcode::MOVSX => write!(f, "{}", "movsx"),
&Opcode::SETO => write!(f, "{}", "seto"),
&Opcode::SETNO => write!(f, "{}", "setno"),
@@ -387,11 +397,10 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::SUBSS |
Opcode::MULSS |
Opcode::DIVSS |
- Opcode::MOVDDUP |
- Opcode::MOVSLDUP |
Opcode::HADDPS |
Opcode::HSUBPS |
Opcode::ADDSUBPS |
+ Opcode::XADD|
Opcode::DIV |
Opcode::IDIV |
Opcode::MUL |
@@ -415,6 +424,12 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::ADD |
Opcode::ADC |
Opcode::SUB |
+ Opcode::BT |
+ Opcode::BTS |
+ Opcode::BTR |
+ Opcode::BTC |
+ Opcode::BSF |
+ Opcode::BSR |
Opcode::IMUL => { write!(out, "{}", colors.arithmetic_op(self)) }
Opcode::POPF |
Opcode::PUSHF |
@@ -471,6 +486,8 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::STC |
Opcode::STI |
Opcode::STD |
+ Opcode::MOVDDUP |
+ Opcode::MOVSLDUP |
Opcode::MOV |
Opcode::MOVSD |
Opcode::CBW |
@@ -482,9 +499,12 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::MOVS |
Opcode::INS |
Opcode::OUTS |
+ Opcode::MOVSX_b |
+ Opcode::MOVSX_w |
Opcode::MOVZX_b |
Opcode::MOVZX_w |
Opcode::MOVSX |
+ Opcode::MOVSXD |
Opcode::XCHG |
Opcode::CMOVA |
Opcode::CMOVB |
@@ -627,6 +647,7 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi
}
};
match self.opcode {
+ Opcode::MOVSX_b |
Opcode::MOVZX_b => {
match context.and_then(|xs| xs[1].as_ref()) {
Some(s) => { write!(out, ", {}", s) }
@@ -653,6 +674,7 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi
}
}
},
+ Opcode::MOVSX_w |
Opcode::MOVZX_w => {
match context.and_then(|xs| xs[1].as_ref()) {
Some(s) => { write!(out, ", {}", s) }
diff --git a/src/lib.rs b/src/lib.rs
index 95e727a..7dcfb5a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -236,6 +236,13 @@ pub enum Segment {
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Opcode {
+ XADD,
+ BT,
+ BTS,
+ BTC,
+ BTR,
+ BSF,
+ BSR,
MOVSS,
ADDSS,
SUBSS,
@@ -266,9 +273,12 @@ pub enum Opcode {
CVTSS2SI,
CVTSS2SD,
LDDQU,
+ MOVSX_b,
+ MOVSX_w,
MOVZX_b,
MOVZX_w,
MOVSX,
+ MOVSXD,
SAR,
SAL,
SHR,
@@ -654,6 +664,7 @@ pub enum OperandCode {
ModRM_0x0f00,
ModRM_0x0f01,
ModRM_0x0fae,
+ ModRM_0x0fba,
Rq_Cq_0,
Rq_Dq_0,
Cq_Rq_0,
@@ -703,6 +714,7 @@ pub enum OperandCode {
Gb_Eb,
Gv_Eb,
Gv_Ew,
+ Gv_Ed,
Gv_Ev,
G_E_xmm,
Gv_M,
@@ -1013,6 +1025,11 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mu
instruction.opcode = Opcode::UD2;
Ok(OperandCode::Nothing)
}
+ 0x0d => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::NOP;
+ Ok(OperandCode::Ev)
+ }
0x1f => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::NOP;
@@ -1255,6 +1272,11 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mu
instruction.opcode = Opcode::CPUID;
Ok(OperandCode::Nothing)
}
+ 0xa3 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::BT;
+ Ok(OperandCode::Gv_Ev)
+ }
0xa8 => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::PUSH;
@@ -1269,6 +1291,11 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mu
instruction.prefixes = prefixes;
Ok(OperandCode::ModRM_0x0fae)
}
+ 0xaf => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::IMUL;
+ Ok(OperandCode::Gv_Ev)
+ }
0xb0 => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::CMPXCHG;
@@ -1289,6 +1316,45 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mu
instruction.opcode = Opcode::MOVZX_w;
Ok(OperandCode::Gv_Ew)
}
+ 0xba => {
+ instruction.prefixes = prefixes;
+ Ok(OperandCode::ModRM_0x0fba)
+ }
+ 0xbb => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::BTC;
+ Ok(OperandCode::Gv_Ev)
+ }
+ 0xbc => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::BSF;
+ Ok(OperandCode::Gv_Ev)
+ }
+ 0xbd => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::BSR;
+ Ok(OperandCode::Gv_Ev)
+ }
+ 0xbe => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOVSX_b;
+ Ok(OperandCode::Gv_Eb)
+ }
+ 0xbf => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOVSX_w;
+ Ok(OperandCode::Gv_Ew)
+ }
+ 0xc0 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::XADD;
+ Ok(OperandCode::Eb_Gb)
+ }
+ 0xc1 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::XADD;
+ Ok(OperandCode::Ev_Gv)
+ }
_ => {
Err(format!("Unknown opcode: 0f{:x}", b))
}
@@ -1391,6 +1457,11 @@ fn read_opcode<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mut Instr
instruction.opcode = op;
return Ok(OperandCode::Zv(x));
},
+ 0x63 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOVSXD;
+ return Ok(OperandCode::Gv_Ed);
+ },
0x64 => {
prefixes.set_fs();
alternate_opcode_map = None;
@@ -1577,12 +1648,12 @@ fn read_opcode<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mut Instr
0x9c => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::PUSHF;
- return Ok(OperandCode::Fw);
+ return Ok(OperandCode::Nothing);
},
0x9d => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::POPF;
- return Ok(OperandCode::Fw);
+ return Ok(OperandCode::Nothing);
},
0x9e => {
instruction.prefixes = prefixes;
@@ -1768,6 +1839,20 @@ fn read_opcode<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mut Instr
instruction.opcode = Opcode::Invalid;
return Ok(operand);
},
+ 0xdc => {
+ // TODO: WRONG
+ // x87 instructions
+ instruction.opcode = Opcode::NOP;
+ let _ = read_imm_unsigned(bytes_iter, 2, length)?;
+ return Ok(OperandCode::Nothing);
+ }
+ 0xdd => {
+ // x87 instructions
+ // TODO: WRONG
+ instruction.opcode = Opcode::NOP;
+ let _ = read_imm_unsigned(bytes_iter, 2, length)?;
+ return Ok(OperandCode::Nothing);
+ }
// TODO: GAP
0xe8 => {
instruction.prefixes = prefixes;
@@ -2631,6 +2716,26 @@ fn read_operands<T: Iterator<Item=u8>>(
}
},
// TODO: verify M
+ OperandCode::Gv_Ed => {
+ let opwidth = 4;
+ // TODO: ...
+ let modrm = match bytes_iter.next() {
+ Some(b) => b,
+ None => return Err("Out of bytes".to_string())
+ };
+ *length += 1;
+ let (mod_bits, r, m) = octets_of(modrm);
+
+// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);
+ match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1], length) {
+ Ok(()) => {
+ instruction.operands[0] =
+ Operand::Register(RegSpec::gp_from_parts(r, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present()));
+ Ok(())
+ },
+ Err(reason) => Err(reason)
+ }
+ },
OperandCode::Gv_Ev | OperandCode::Gv_M => {
let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes);
// TODO: ...
@@ -2947,7 +3052,8 @@ fn read_operands<T: Iterator<Item=u8>>(
instruction.operands = [Operand::Nothing, Operand::Nothing];
Ok(())
} else {
- panic!("Unsupported instruction: 0x0f01 with modrm: 11 110 r >= 2");
+ // panic!("Unsupported instruction: 0x0f01 with modrm: 11 110 r >= 2");
+ Err("unsupported 0x0f01 variant".to_string())
}
} else {
instruction.opcode = Opcode::INVLPG;
@@ -3049,6 +3155,47 @@ fn read_operands<T: Iterator<Item=u8>>(
_ => { unreachable!("r < 6"); }
}
}
+ OperandCode::ModRM_0x0fba => {
+ let opwidth = imm_width_from_prefixes_64(SizeCode::vq, &instruction.prefixes);
+ let modrm = match bytes_iter.next() {
+ Some(b) => b,
+ None => return Err("Out of bytes".to_string())
+ };
+ *length += 1;
+ let (mod_bits, r, m) = octets_of(modrm);
+ match r {
+ 0 | 1 | 2 | 3 => {
+ instruction.opcode = Opcode::Invalid;
+ return Err("invalid instruction".to_string());
+ },
+ 4 => {
+ instruction.opcode = Opcode::BT;
+ }
+ 5 => {
+ instruction.opcode = Opcode::BTS;
+ }
+ 6 => {
+ instruction.opcode = Opcode::BTR;
+ }
+ 7 => {
+ instruction.opcode = Opcode::BTC;
+ }
+ _ => {
+ unreachable!("r < 8");
+ }
+ }
+
+ read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0], length)?;
+
+ match read_imm_signed(bytes_iter, 1, 1, length) {
+ Ok(op) => {
+ instruction.operands[1] = op;
+ Ok(())
+ },
+ Err(reason) => Err(reason)
+ }
+ }
+
OperandCode::Rq_Cq_0 => {
let modrm = match bytes_iter.next() {
Some(b) => b,
diff --git a/test/test.rs b/test/test.rs
index 3a7aee9..5d5f3b0 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -98,6 +98,7 @@ fn test_mov() {
test_display(&[0x0f, 0xb7, 0x06], "movzx eax, word [rsi]");
test_display(&[0x89, 0x55, 0x94], "mov [rbp - 0x6c], edx");
test_display(&[0x65, 0x4c, 0x89, 0x04, 0x25, 0xa8, 0x01, 0x00, 0x00], "mov gs:[0x1a8], r8");
+ test_display(&[0x0f, 0xbe, 0x83, 0xb4, 0x00, 0x00, 0x00], "movsx eax, byte [rbx + 0xb4]");
test_display(&[0x48, 0x63, 0x04, 0xba], "movsxd rax, [rdx + rdi * 4]");
}
@@ -146,7 +147,14 @@ fn test_push_pop() {
}
#[test]
+fn test_bitwise() {
+ test_display(&[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
+ test_display(&[0x48, 0x0f, 0xa3, 0xd0], "bt rax, rdx");
+}
+
+#[test]
fn test_misc() {
+ test_display(&[0x9c], "pushf");
test_display(&[0x48, 0x98], "cdqe");
test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop cs:[rax + rax]");
test_display(&[0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00], "nop cs:[rax + rax]");