From 5223427b217cc567deb55ea420b8da58aea64d68 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 21 Mar 2021 02:48:11 -0700 Subject: complete CET support, add UINTR, add missing VORP{S,D}, other cleanup --- src/long_mode/display.rs | 26 +++++++++++ src/long_mode/mod.rs | 116 ++++++++++++++++++++++++++++++++++++++-------- src/long_mode/vex.rs | 10 ++++ test/long_mode/display.rs | 2 +- test/long_mode/mod.rs | 30 ++++++++++-- 5 files changed, 160 insertions(+), 24 deletions(-) diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 8f7bd9b..5c733a2 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -848,6 +848,8 @@ const MNEMONICS: &[&'static str] = &[ "vpalignr", "vandps", "vandpd", + "vorps", + "vorpd", "vandnps", "vandnpd", "vpand", @@ -1285,6 +1287,11 @@ const MNEMONICS: &[&'static str] = &[ // CET "wruss", "wrss", + "incssp", + "saveprevssp", + "setssbsy", + "clrssbsy", + "rstorssp", // TDX "tdcall", @@ -1296,6 +1303,13 @@ const MNEMONICS: &[&'static str] = &[ "tpause", "umonitor", "umwait", + + // UINTR + "uiret", + "testui", + "clui", + "stui", + "senduipi", ]; impl Opcode { @@ -1462,6 +1476,8 @@ impl > Colorize> Colorize { write!(out, "{}", colors.platform_op(self)) } Opcode::CRC32 | @@ -2330,6 +2351,11 @@ impl > Colorize>(decoder: &InstDecoder, mut bytes_iter 0x1d => { instruction.opcode = Opcode::PF2ID; } - 0x59 => { - instruction.opcode = Opcode::PMULHRW; - } 0x8a => { instruction.opcode = Opcode::PFNACC; } @@ -7293,9 +7306,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 0xbb => { instruction.opcode = Opcode::PSWAPD; } - 0xbe => { - instruction.opcode = Opcode::PFPNACC; - } 0xbf => { instruction.opcode = Opcode::PAVGUSB; } @@ -7414,9 +7424,10 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = Opcode::VMXON; instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; if instruction.operands[0] == OperandSpec::RegMMM { - // this would be invalid as `vmxon`, so fall back to the parse as - // f3-prefixed rdrand - instruction.opcode = Opcode::RDRAND; + // invalid as `vmxon`, reg-form is `senduipi` + instruction.opcode = Opcode::SENDUIPI; + // and the operand is always a qword register + instruction.modrm_mmm.bank = RegisterBank::Q; } instruction.operand_count = 1; } @@ -8301,20 +8312,69 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } else if r == 5 { let mod_bits = modrm >> 6; if mod_bits != 0b11 { - instruction.opcode = Opcode::Invalid; - instruction.operands[0] = OperandSpec::Nothing; - instruction.operand_count = 0; - return Err(DecodeError::InvalidOpcode); + if !instruction.prefixes.rep() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::RSTORSSP; + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 8, length)?; + instruction.operand_count = 1; + return Ok(()); } let m = modrm & 7; match m { + 0b000 => { + if !instruction.prefixes.rep() || instruction.prefixes.operand_size() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::SETSSBSY; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + 0b010 => { + if !instruction.prefixes.rep() || instruction.prefixes.operand_size() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::SAVEPREVSSP; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + 0b100 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::UIRET; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + } + 0b101 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::TESTUI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + } 0b110 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::CLUI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.operand_size() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } instruction.opcode = Opcode::RDPKRU; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } 0b111 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::STUI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.operand_size() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } instruction.opcode = Opcode::WRPKRU; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; @@ -8509,13 +8569,21 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } + 5 => { + instruction.opcode = Opcode::INCSSP; + let opwidth = if instruction.prefixes.rex().w() { + RegisterBank::Q + } else { + RegisterBank::D + }; + instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + } 6 => { instruction.opcode = Opcode::UMONITOR; - instruction.modrm_rrr = RegSpec { - bank: RegisterBank::Q, - num: m + if instruction.prefixes.rex().x() { 0b1000 } else { 0 }, - }; - instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), RegisterBank::Q); + instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } _ => { @@ -8525,7 +8593,17 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } return Ok(()); } else { - return Err(DecodeError::InvalidOperand); + match r { + 6 => { + instruction.opcode = Opcode::CLRSSBSY; + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 8, length)?; + instruction.operand_count = 1; + return Ok(()); + } + _ => { + return Err(DecodeError::InvalidOperand); + } + } } } diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs index 71a5724..41f5c29 100644 --- a/src/long_mode/vex.rs +++ b/src/long_mode/vex.rs @@ -952,6 +952,11 @@ fn read_vex_instruction>(opcode_map: VEXOpcodeMap, bytes: & } else { VEXOperandCode::G_V_E_xmm }), + 0x56 => (Opcode::VORPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), 0x57 => (Opcode::VXORPS, if L { VEXOperandCode::G_V_E_ymm } else { @@ -1099,6 +1104,11 @@ fn read_vex_instruction>(opcode_map: VEXOpcodeMap, bytes: & } else { VEXOperandCode::G_V_E_xmm }), + 0x56 => (Opcode::VORPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), 0x57 => (Opcode::VXORPD, if L { VEXOperandCode::G_V_E_ymm } else { diff --git a/test/long_mode/display.rs b/test/long_mode/display.rs index 7017270..2d1a540 100644 --- a/test/long_mode/display.rs +++ b/test/long_mode/display.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use yaxpeax_arch::{AddressBase, Decoder, LengthedInstruction}; -use yaxpeax_x86::long_mode::{DisplayStyle, InstDecoder, Opcode}; +use yaxpeax_x86::long_mode::{DisplayStyle, InstDecoder}; fn test_display(data: &[u8], expected: &'static str) { test_display_under(&InstDecoder::default(), data, expected); diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 130a7ab..fff10a2 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -5,7 +5,7 @@ mod display; use std::fmt::Write; use yaxpeax_arch::{AddressBase, Decoder, LengthedInstruction}; -use yaxpeax_x86::long_mode::{InstDecoder, Opcode}; +use yaxpeax_x86::long_mode::InstDecoder; fn test_invalid(data: &[u8]) { test_invalid_under(&InstDecoder::default(), data); @@ -904,10 +904,10 @@ fn test_0f01() { test_invalid(&[0x0f, 0x01, 0xe9]); test_invalid(&[0x0f, 0x01, 0xea]); test_invalid(&[0x0f, 0x01, 0xeb]); - test_invalid(&[0x0f, 0x01, 0xec]); - test_invalid(&[0x0f, 0x01, 0xed]); test_display(&[0x0f, 0x01, 0xee], "rdpkru"); test_display(&[0x0f, 0x01, 0xef], "wrpkru"); + test_invalid(&[0xf2, 0x0f, 0x01, 0xee]); + test_invalid(&[0xf2, 0x0f, 0x01, 0xef]); test_display(&[0x4f, 0x0f, 0x01, 0xf0], "lmsw r8w"); test_display(&[0x0f, 0x01, 0xf0], "lmsw ax"); test_display(&[0x0f, 0x01, 0xf1], "lmsw cx"); @@ -1548,6 +1548,8 @@ fn test_vex() { test_instr(&[0xc5, 0xe1, 0x54, 0x03], "vandps xmm0, xmm3, [rbx]"); test_instr(&[0xc5, 0xe0, 0x55, 0x03], "vandnpd xmm0, xmm3, [rbx]"); test_instr(&[0xc5, 0xe1, 0x55, 0x03], "vandnps xmm0, xmm3, [rbx]"); + test_instr(&[0xc5, 0xe0, 0x56, 0x03], "vorpd xmm0, xmm3, [rbx]"); + test_instr(&[0xc5, 0xe1, 0x56, 0x03], "vorps xmm0, xmm3, [rbx]"); } #[test] @@ -1801,7 +1803,6 @@ fn test_sha() { fn test_vmx() { test_display(&[0x0f, 0xc7, 0x3f], "vmptrst [rdi]"); test_display(&[0x0f, 0xc7, 0x37], "vmptrld [rdi]"); - test_display(&[0xf3, 0x0f, 0xc7, 0xf7], "rdrand edi"); test_display(&[0xf3, 0x0f, 0xc7, 0x37], "vmxon [rdi]"); test_display(&[0x66, 0x0f, 0xc7, 0xf7], "rdrand di"); test_display(&[0x66, 0x0f, 0xc7, 0x37], "vmclear [rdi]"); @@ -2274,10 +2275,17 @@ fn test_cet() { // clrssbsy f3 0f ae /6 // endbr64 f3 0f ae fa // endbr32 f3 0f ae fb + test_display(&[0xf3, 0x4f, 0x0f, 0xae, 0xe9], "incssp r9"); + test_display(&[0xf3, 0x0f, 0xae, 0xe9], "incssp ecx"); test_display(&[0x3e, 0x4f, 0x0f, 0x38, 0xf6, 0x23], "wrss [r11], r12"); test_display(&[0x66, 0x0f, 0x38, 0xf5, 0x47, 0xe9], "wruss [rdi - 0x17], eax"); test_invalid(&[0x0f, 0x38, 0xf5, 0x47, 0xe9]); test_invalid(&[0x66, 0x3e, 0x65, 0x3e, 0x0f, 0x38, 0xf5, 0xf0]); + test_display(&[0xf3, 0x0f, 0x01, 0xe8], "setssbsy"); + test_display(&[0xf3, 0x0f, 0x01, 0xea], "saveprevssp"); + test_display(&[0xf3, 0x0f, 0x01, 0x29], "rstorssp [rcx]"); + test_display(&[0xf3, 0x66, 0x0f, 0x01, 0x29], "rstorssp [rcx]"); + test_display(&[0xf3, 0x0f, 0xae, 0x30], "clrssbsy [rax]"); } #[test] @@ -2329,6 +2337,20 @@ fn test_key_locker() { test_display(&[0xf3, 0x0f, 0x38, 0xfb, 0xde], "encodekey256 ebx, esi"); } +// these uinter test cases come from llvm: +// https://reviews.llvm.org/differential/changeset/?ref=2226860 +#[test] +fn test_uintr() { + test_display(&[0xf3, 0x0f, 0x01, 0xec], "uiret"); + test_display(&[0xf3, 0x0f, 0x01, 0xed], "testui"); + test_display(&[0xf3, 0x0f, 0x01, 0xee], "clui"); + test_display(&[0xf3, 0x0f, 0x01, 0xef], "stui"); + test_display(&[0xf3, 0x0f, 0xc7, 0xf0], "senduipi rax"); + test_display(&[0xf3, 0x0f, 0xc7, 0xf2], "senduipi rdx"); + test_display(&[0xf3, 0x41, 0x0f, 0xc7, 0xf0], "senduipi r8"); + test_display(&[0xf3, 0x41, 0x0f, 0xc7, 0xf5], "senduipi r13"); +} + // started shipping in sapphire rapids #[test] fn test_enqcmd() { -- cgit v1.1