diff options
| -rw-r--r-- | CHANGELOG | 2 | ||||
| -rw-r--r-- | src/protected_mode/display.rs | 6 | ||||
| -rw-r--r-- | src/protected_mode/mod.rs | 29 | ||||
| -rw-r--r-- | src/real_mode/display.rs | 6 | ||||
| -rw-r--r-- | src/real_mode/mod.rs | 29 | ||||
| -rw-r--r-- | test/protected_mode/mod.rs | 2 | ||||
| -rw-r--r-- | test/real_mode/mod.rs | 2 | 
7 files changed, 74 insertions, 2 deletions
@@ -12,6 +12,8 @@  * adjust test structure so that exhaustive tests can be `#[ignored]` and    explicitly run anyway for completeness. this means the ignored at&t tests now    are both ignored and appear to succeed when run. +* support `9a` encoding of `callf` with absolute segment/address operand +  - this encoding is only present in 32-bit and 16-bit modes  ## 1.1.4  * fix reachable unreachable under `DisplayStyle::C` in 64-, 32-, and 16-bit modes diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs index 69cdbc7..4416141 100644 --- a/src/protected_mode/display.rs +++ b/src/protected_mode/display.rs @@ -163,6 +163,12 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {                  write!(f, "{}",                      colors.number(signed_i32_hex(imm)))              }, +            &Operand::AbsoluteFarAddress { segment, address } => { +                write!(f, "{}:{}", +                    colors.number(u16_hex(segment as u16)), +                    colors.number(u32_hex(address as u32)), +                ) +            },              &Operand::Register(ref spec) => {                  f.write_str(regspec_label(spec))              } diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index dd63d32..5457b9d 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -389,6 +389,9 @@ pub enum Operand {      /// use; the instruction's `operand_count` should be reduced so as to make this invisible to      /// library clients.      Nothing, +    /// absolute far call. this is only used for `9a` far calls with absolute `u16:u{16,32}` +    /// operand, and so only exists in 32- and 16-bit modes. +    AbsoluteFarAddress { segment: u16, address: u32 },  }  impl OperandSpec { @@ -450,6 +453,7 @@ impl OperandSpec {              OperandSpec::RegVex_maskmerge |              OperandSpec::Reg4 |              OperandSpec::ImmInDispField | +            OperandSpec::AbsoluteFarAddress |              OperandSpec::Nothing => {                  false              } @@ -683,6 +687,12 @@ impl Operand {                      Operand::RegIndexBaseScaleDisp(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32)                  }              } +            OperandSpec::AbsoluteFarAddress => { +                Operand::AbsoluteFarAddress { +                    segment: inst.disp as u16, +                    address: inst.imm as u32, +                } +            }          }      }      /// returns `true` if this operand implies a memory access, `false` otherwise. @@ -721,6 +731,7 @@ impl Operand {              Operand::RegisterMaskMerge(_, _, _) |              Operand::RegisterMaskMergeSae(_, _, _, _) |              Operand::RegisterMaskMergeSaeNoround(_, _, _) | +            Operand::AbsoluteFarAddress { .. } |              Operand::Nothing => {                  false              } @@ -2639,6 +2650,8 @@ enum OperandSpec {      RegIndexBaseDisp_mask,      RegIndexBaseScale_mask,      RegIndexBaseScaleDisp_mask, +    // u16:u{16,32} immediate address for a far call +    AbsoluteFarAddress,  }  // the Hash, Eq, and PartialEq impls here are possibly misleading. @@ -5180,6 +5193,7 @@ enum OperandCode {      PMOVX_E_G_xmm = OperandCodeBuilder::new().operand_case(110).bits(),      G_Ev_xmm_Ib = OperandCodeBuilder::new().operand_case(111).bits(),      G_E_mm_Ib = OperandCodeBuilder::new().operand_case(112).bits(), +    AbsFar = OperandCodeBuilder::new().operand_case(113).bits(),  }  const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ @@ -5404,7 +5418,7 @@ const OPCODES: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R7),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_AA),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_DA), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::CALLF), OperandCode::AbsFar),      OpcodeRecord(Interpretation::Instruction(Opcode::WAIT), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::PUSHF), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::POPF), OperandCode::Nothing), @@ -8568,6 +8582,19 @@ fn unlikely_operands<      S: DescriptionSink<FieldDescription>  >(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, sink: &mut S) -> Result<(), DecodeError> {      match operand_code { +        OperandCode::AbsFar => { +            instruction.operands[0] = OperandSpec::AbsoluteFarAddress; +            instruction.operand_count = 1; +            instruction.mem_size = 0; +            // read segment +            let addr_size = if instruction.prefixes.operand_size() { +                2 +            } else { +                4 +            }; +            instruction.imm = read_num(words, addr_size)?; +            instruction.disp = read_num(words, 2)? as u16 as u32; +        }          OperandCode::G_E_mm_Ib => {              let modrm = read_modrm(words)?; diff --git a/src/real_mode/display.rs b/src/real_mode/display.rs index 070ca56..6f6eb74 100644 --- a/src/real_mode/display.rs +++ b/src/real_mode/display.rs @@ -163,6 +163,12 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {                  write!(f, "{}",                      colors.number(signed_i32_hex(imm)))              }, +            &Operand::AbsoluteFarAddress { segment, address } => { +                write!(f, "{}:{}", +                    colors.number(u16_hex(segment as u16)), +                    colors.number(u32_hex(address as u32)), +                ) +            },              &Operand::Register(ref spec) => {                  f.write_str(regspec_label(spec))              } diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs index d7fda17..8749ae2 100644 --- a/src/real_mode/mod.rs +++ b/src/real_mode/mod.rs @@ -389,6 +389,9 @@ pub enum Operand {      /// use; the instruction's `operand_count` should be reduced so as to make this invisible to      /// library clients.      Nothing, +    /// absolute far call. this is only used for `9a` far calls with absolute `u16:u{16,32}` +    /// operand, and so only exists in 32- and 16-bit modes. +    AbsoluteFarAddress { segment: u16, address: u32 },  }  impl OperandSpec { @@ -450,6 +453,7 @@ impl OperandSpec {              OperandSpec::RegVex_maskmerge |              OperandSpec::Reg4 |              OperandSpec::ImmInDispField | +            OperandSpec::AbsoluteFarAddress |              OperandSpec::Nothing => {                  false              } @@ -683,6 +687,12 @@ impl Operand {                      Operand::RegIndexBaseScaleDisp(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32)                  }              } +            OperandSpec::AbsoluteFarAddress => { +                Operand::AbsoluteFarAddress { +                    segment: inst.disp as u16, +                    address: inst.imm as u32, +                } +            }          }      }      /// returns `true` if this operand implies a memory access, `false` otherwise. @@ -721,6 +731,7 @@ impl Operand {              Operand::RegisterMaskMerge(_, _, _) |              Operand::RegisterMaskMergeSae(_, _, _, _) |              Operand::RegisterMaskMergeSaeNoround(_, _, _) | +            Operand::AbsoluteFarAddress { .. } |              Operand::Nothing => {                  false              } @@ -2639,6 +2650,8 @@ enum OperandSpec {      RegIndexBaseDisp_mask,      RegIndexBaseScale_mask,      RegIndexBaseScaleDisp_mask, +    // u16:u{16,32} immediate address for a far call +    AbsoluteFarAddress,  }  // the Hash, Eq, and PartialEq impls here are possibly misleading. @@ -5180,6 +5193,7 @@ enum OperandCode {      PMOVX_E_G_xmm = OperandCodeBuilder::new().operand_case(110).bits(),      G_Ev_xmm_Ib = OperandCodeBuilder::new().operand_case(111).bits(),      G_E_mm_Ib = OperandCodeBuilder::new().operand_case(112).bits(), +    AbsFar = OperandCodeBuilder::new().operand_case(113).bits(),  }  const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ @@ -5404,7 +5418,7 @@ const OPCODES: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R7),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_AA),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_DA), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::CALLF), OperandCode::AbsFar),      OpcodeRecord(Interpretation::Instruction(Opcode::WAIT), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::PUSHF), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::POPF), OperandCode::Nothing), @@ -8570,6 +8584,19 @@ fn unlikely_operands<      S: DescriptionSink<FieldDescription>  >(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, sink: &mut S) -> Result<(), DecodeError> {      match operand_code { +        OperandCode::AbsFar => { +            instruction.operands[0] = OperandSpec::AbsoluteFarAddress; +            instruction.operand_count = 1; +            instruction.mem_size = 0; +            // read segment +            let addr_size = if instruction.prefixes.operand_size() { +                4 +            } else { +                2 +            }; +            instruction.imm = read_num(words, addr_size)?; +            instruction.disp = read_num(words, 2)? as u16 as u32; +        }          OperandCode::G_E_mm_Ib => {              let modrm = read_modrm(words)?; diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs index 9cda6be..93f4b8f 100644 --- a/test/protected_mode/mod.rs +++ b/test/protected_mode/mod.rs @@ -2393,6 +2393,8 @@ fn prefixed_f30f() {  #[test]  fn only_32bit() { +    test_display(&[0x9a, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66], "callf 0x6655:0x44332211"); +    test_display(&[0x66, 0x9a, 0x11, 0x22, 0x33, 0x44], "callf 0x4433:0x2211");      test_display(&[0x67, 0xac], "lods al, byte ds:[si]");      test_display(&[0x67, 0xae], "scas byte es:[di], al");      test_display(&[0xac], "lods al, byte ds:[esi]"); diff --git a/test/real_mode/mod.rs b/test/real_mode/mod.rs index dcd124c..27ef2f6 100644 --- a/test/real_mode/mod.rs +++ b/test/real_mode/mod.rs @@ -78,6 +78,8 @@ fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str  #[test]  fn only_16bit() { +    test_display(&[0x66, 0x9a, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66], "callf 0x6655:0x44332211"); +    test_display(&[0x9a, 0x11, 0x22, 0x33, 0x44], "callf 0x4433:0x2211");      test_display(&[0xac], "lods al, byte ds:[si]");      test_display(&[0xae], "scas byte es:[di], al");      test_display(&[0x67, 0xac], "lods al, byte ds:[esi]");  | 
