aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-12-16 00:30:10 -0800
committeriximeow <me@iximeow.net>2020-01-12 16:10:14 -0800
commitf23d12996aeb4f6e1dbf65e4c8e39376303425c8 (patch)
tree98be5ad82a17a34b02dff470dcfc4eb907a05a73
parent81147159d3e8a11a0a97d112bd631b5aeeaa73c6 (diff)
support missing sse3 instructions, add tests for sse3 instructions
-rw-r--r--src/lib.rs32
-rw-r--r--test/test.rs67
2 files changed, 83 insertions, 16 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 1d798ab..15cee14 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2433,7 +2433,6 @@ pub enum OperandCode {
Gv_Eb = 0x60,
Gv_Ew = 0x61,
Gdq_Ed = 0x62,
- G_E_xmm = 0x63,
G_E_mm_Ib = 0x64,
G_E_xmm_Ib = 0x65,
AL_Ib = 0x66,
@@ -2490,6 +2489,8 @@ pub enum OperandCode {
G_U_mm = 0xf1,
Ev_Gv_Ib = 0xf3,
Ev_Gv_CL = 0xf5,
+ G_M_xmm = 0xf7,
+ G_E_xmm = 0xf9,
}
fn base_opcode_map(v: u8) -> Opcode {
@@ -2649,8 +2650,8 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::HADDPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPD), OperandCode::G_E_xmm),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
// 0x80
@@ -2739,7 +2740,7 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
// 0xd0
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPD), OperandCode::G_E_xmm),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
@@ -3054,7 +3055,7 @@ const OPCODE_F20F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
// 0xf0
- OpcodeRecord(Interpretation::Instruction(Opcode::LDDQU), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LDDQU), OperandCode::G_M_xmm),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
@@ -4758,16 +4759,21 @@ pub fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
instruction.modrm_mmm.num &= 0b111;
instruction.operand_count = 2;
},
- OperandCode::G_E_xmm => {
- let modrm = read_modrm(&mut bytes_iter, instruction, length)?;
- bytes_read = 1;
-
-// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);
- instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
- instruction.modrm_rrr =
- RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X);
+ op @ OperandCode::G_M_xmm |
+ op @ OperandCode::G_E_xmm => {
+ instruction.modrm_rrr.bank = RegisterBank::X;
instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
instruction.operand_count = 2;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ if op == OperandCode::G_M_xmm {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ } else {
+ // fix the register to XMM
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ }
+ }
},
OperandCode::G_E_mm_Ib => {
let modrm = read_modrm(&mut bytes_iter, instruction, length)?;
diff --git a/test/test.rs b/test/test.rs
index b8c14a7..e2c52fe 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -28,7 +28,7 @@ fn test_invalid(data: &[u8]) {
fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) {
if let Some(inst) = decoder.decode(data.into_iter().cloned()) {
- assert_eq!(inst.opcode, yaxpeax_x86::Opcode::Invalid);
+ assert_eq!(inst.opcode, yaxpeax_x86::Opcode::Invalid, "decoded {:?} from {:02x?} under decoder {}", inst.opcode, data, decoder);
} else {
// this is fine
}
@@ -48,15 +48,16 @@ fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str
let text = format!("{}", instr);
assert!(
text == expected,
- "display error for {}:\n decoded: {:?}\n displayed: {}\n expected: {}\n",
+ "display error for {}:\n decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n",
hex,
instr,
+ decoder,
text,
expected
);
},
None => {
- assert!(false, "decode error for {}:\n expected: {}\n", hex, expected);
+ assert!(false, "decode error for {} under decoder {}:\n expected: {}\n", hex, decoder, expected);
}
}
}
@@ -97,6 +98,66 @@ fn test_cvt() {
}
#[test]
+fn test_sse3() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_sse3(), bytes, text);
+ test_invalid_under(&InstDecoder::minimal(), bytes);
+ // avx doesn't imply older instructions are necessarily valid
+ test_invalid_under(&InstDecoder::minimal().with_avx(), bytes);
+ // sse4 doesn't imply older instructions are necessarily valid
+ test_invalid_under(&InstDecoder::minimal().with_sse4_1(), bytes);
+ test_invalid_under(&InstDecoder::minimal().with_sse4_2(), bytes);
+ }
+
+ fn test_instr_invalid(bytes: &[u8]) {
+ test_invalid_under(&InstDecoder::minimal().with_sse3(), bytes);
+ test_invalid_under(&InstDecoder::default(), bytes);
+ }
+
+ test_instr(&[0xf2, 0x0f, 0xf0, 0x0f], "lddqu xmm1, [rdi]");
+ test_instr_invalid(&[0xf2, 0x0f, 0xf0, 0xcf]);
+ test_instr(&[0xf2, 0x0f, 0xd0, 0x0f], "addsubps xmm1, [rdi]");
+ test_instr(&[0xf2, 0x0f, 0xd0, 0xcf], "addsubps xmm1, xmm7");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0xd0, 0xcf], "addsubps xmm9, xmm15");
+ test_instr(&[0x66, 0x0f, 0xd0, 0x0f], "addsubpd xmm1, [rdi]");
+ test_instr(&[0x66, 0x0f, 0xd0, 0xcf], "addsubpd xmm1, xmm7");
+ test_instr(&[0x66, 0x4f, 0x0f, 0xd0, 0xcf], "addsubpd xmm9, xmm15");
+
+ test_instr(&[0xf2, 0x0f, 0x7c, 0x0f], "haddps xmm1, [rdi]");
+ test_instr(&[0xf2, 0x0f, 0x7c, 0xcf], "haddps xmm1, xmm7");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x7c, 0xcf], "haddps xmm9, xmm15");
+ test_instr(&[0x66, 0x0f, 0x7c, 0x0f], "haddpd xmm1, [rdi]");
+ test_instr(&[0x66, 0x0f, 0x7c, 0xcf], "haddpd xmm1, xmm7");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x7c, 0xcf], "haddpd xmm9, xmm15");
+
+ test_instr(&[0xf2, 0x0f, 0x7d, 0x0f], "hsubps xmm1, [rdi]");
+ test_instr(&[0xf2, 0x0f, 0x7d, 0xcf], "hsubps xmm1, xmm7");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x7d, 0xcf], "hsubps xmm9, xmm15");
+ test_instr(&[0x66, 0x0f, 0x7d, 0x0f], "hsubpd xmm1, [rdi]");
+ test_instr(&[0x66, 0x0f, 0x7d, 0xcf], "hsubpd xmm1, xmm7");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x7d, 0xcf], "hsubpd xmm9, xmm15");
+
+ test_instr(&[0xf3, 0x0f, 0x12, 0x0f], "movsldup xmm1, [rdi]");
+ test_instr(&[0xf3, 0x0f, 0x12, 0xcf], "movsldup xmm1, xmm7");
+ test_instr(&[0xf3, 0x4f, 0x0f, 0x12, 0xcf], "movsldup xmm9, xmm15");
+ test_instr(&[0xf3, 0x0f, 0x16, 0x0f], "movshdup xmm1, [rdi]");
+ test_instr(&[0xf3, 0x0f, 0x16, 0xcf], "movshdup xmm1, xmm7");
+ test_instr(&[0xf3, 0x4f, 0x0f, 0x16, 0xcf], "movshdup xmm9, xmm15");
+
+ test_instr(&[0xf2, 0x0f, 0x12, 0x0f], "movddup xmm1, [rdi]");
+ test_instr(&[0xf2, 0x0f, 0x12, 0xcf], "movddup xmm1, xmm7");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x12, 0xcf], "movddup xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x01, 0xc8], "monitor");
+ test_instr(&[0xf2, 0x0f, 0x01, 0xc8], "monitor");
+ test_instr(&[0xf3, 0x0f, 0x01, 0xc8], "monitor");
+
+ test_instr(&[0x66, 0x0f, 0x01, 0xc9], "mwait");
+ test_instr(&[0xf2, 0x0f, 0x01, 0xc9], "mwait");
+ test_instr(&[0xf3, 0x0f, 0x01, 0xc9], "mwait");
+}
+
+#[test]
fn test_0f01() {
// drawn heavily from "Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group
// Number"