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"); | 
