diff --git a/src/disasm.rs b/src/disasm.rs index 3742bca..7e9e375 100644 --- a/src/disasm.rs +++ b/src/disasm.rs @@ -668,7 +668,7 @@ impl Disassembler { // byte extended version let (target, reg) = self.parse_modrm_byte(Some(InstructionWidth::Word))?; let imm = self.parse_byte()?; - Self::modrm_reg_to_grp1(reg, target, ImmediateOperand::Byte(imm))? + Self::modrm_reg_to_grp1(reg, target, ImmediateOperand::Byte(imm).sign_extend())? } 0x84 => modrm_8b_register!(self, TEST), diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 592041d..aeafeeb 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -239,7 +239,25 @@ impl Computer { dest: ModRmTarget, src: ArithmeticOperand, ) -> Result<(), InterpreterError> { - let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs - rhs; + let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| { + // 0x80, with modrm byte selecting mem read from [%bx] is the only + // grp1 instruction, which does not state sign-extension, meaning + // that rhs really is just a byte, which means only the low byte + // of lhs should be compared to. + // With out this match here, the sub logic would sign extend the + // rhs to a word, which is not the desired logic. + match lhs { + ImmediateOperand::Word(lhsw) => match rhs { + ImmediateOperand::Byte(_) => { + let [low, _] = lhsw.to_be_bytes(); + return ImmediateOperand::Byte(low) - rhs; + } + _ => {} + }, + _ => {} + } + lhs - rhs + }; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| { // log::info!("{:?} {:?} {}", lhs, rhs, lhs < rhs); flags.cf = lhs < rhs;