diff options
author | iximeow <me@iximeow.net> | 2019-11-30 17:22:05 -0800 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2020-01-12 16:10:13 -0800 |
commit | 0bb08a980d52db277a6da8758486bac22342a882 (patch) | |
tree | 864d99b950bb4841a01674546acf9be5142ca9e4 | |
parent | 639bcc836b70069e9569b21bd07e5764eba86b66 (diff) |
more careful prefix handling
-rw-r--r-- | src/lib.rs | 58 | ||||
-rw-r--r-- | test/test.rs | 7 |
2 files changed, 35 insertions, 30 deletions
@@ -2911,6 +2911,23 @@ pub fn read_instr<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut Ins let mut alternate_opcode_map: Option<OpcodeMap> = None; // use std::intrinsics::unlikely; let mut prefixes = Prefixes::new(0); + + fn escapes_are_prefixes_actually(prefixes: &mut Prefixes, opc_map: &mut Option<OpcodeMap>) { + match opc_map { + Some(OpcodeMap::Map66) => { + prefixes.set_operand_size(); + }, + Some(OpcodeMap::MapF2) => { + prefixes.set_repnz(); + }, + Some(OpcodeMap::MapF3) => { + prefixes.set_rep(); + }, + None => {} + } + *opc_map = None; + } + let record: OpcodeRecord = loop { // let operand_code = loop { match bytes_iter.next() { @@ -2934,17 +2951,7 @@ pub fn read_instr<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut Ins }, }; if rec.0 == Interpretation::Instruction(Opcode::Invalid) { - match opcode_map { - OpcodeMap::Map66 => { - prefixes.set_operand_size(); - }, - OpcodeMap::MapF2 => { - prefixes.set_repnz(); - }, - OpcodeMap::MapF3 => { - prefixes.set_rep(); - }, - } + escapes_are_prefixes_actually(&mut prefixes, &mut Some(opcode_map)); OPCODE_0F_MAP[opcode_byte as usize] } else { rec @@ -2957,51 +2964,42 @@ pub fn read_instr<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut Ins break record; } else if let Interpretation::Instruction(_) = record.0 { - match alternate_opcode_map { - Some(OpcodeMap::Map66) => { - prefixes.set_operand_size(); - }, - Some(OpcodeMap::MapF2) => { - prefixes.set_repnz(); - }, - Some(OpcodeMap::MapF3) => { - prefixes.set_rep(); - }, - None => {} - } + escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map); break record; } else { + // some prefix seen after we saw rex, but before the 0f escape or an actual + // opcode. so we must forget the rex prefix! + // this is to handle sequences like 41660f21cf + // where if 660f21 were a valid opcode, 41 would apply a rex.b + // prefix, but since 660f21 is not valid, the opcode is interpreted + // as 0f21, where 66 is a prefix, which makes 41 not the last + // prefix before the opcode, and it's discarded. + prefixes.rex_mut().from(0); + escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map); match b { 0x26 => { prefixes.set_es(); - alternate_opcode_map = None; }, 0x2e => { prefixes.set_cs(); - alternate_opcode_map = None; }, 0x36 => { prefixes.set_ss(); - alternate_opcode_map = None; }, 0x3e => { prefixes.set_ds(); - alternate_opcode_map = None; }, 0x64 => { prefixes.set_fs(); - alternate_opcode_map = None; }, 0x65 => { prefixes.set_gs(); - alternate_opcode_map = None; }, 0x66 => { alternate_opcode_map = Some(OpcodeMap::Map66); }, 0x67 => { prefixes.set_address_size(); - alternate_opcode_map = None; }, 0xf0 => { prefixes.set_lock(); diff --git a/test/test.rs b/test/test.rs index dc945e7..30e6eac 100644 --- a/test/test.rs +++ b/test/test.rs @@ -260,6 +260,13 @@ fn vex() { } #[test] +fn strange_prefixing() { + test_display(&[0x45, 0x66, 0x0f, 0x21, 0xc8], "mov rax, dr1"); + test_display(&[0x45, 0xf2, 0x0f, 0x21, 0xc8], "mov rax, dr1"); + test_display(&[0x45, 0xf3, 0x0f, 0x21, 0xc8], "mov rax, dr1"); +} + +#[test] fn prefixed_0f() { test_display(&[0x0f, 0x02, 0xc0], "lar eax, ax"); test_display(&[0x48, 0x0f, 0x02, 0xc0], "lar rax, ax"); |