summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-07-11 23:19:31 +0200
committerAndreas Kling <kling@serenityos.org>2020-07-11 23:57:14 +0200
commit6febad1ef32165821c27262a95621a71a3698346 (patch)
treef806ad7f3026c146520092b1ee1f7267a1ddf24f
parent21837544bbe98def31d32c40a073516f8cd8cf6f (diff)
downloadserenity-6febad1ef32165821c27262a95621a71a3698346.zip
UserspaceEmulator: The generic_RM*_imm8 functions need to sign extend
We are supposed to sign-extend the 8-bit immediate here, "cmp eax, 0xff" is actually "cmp eax, 0xffffffff"
-rw-r--r--DevTools/UserspaceEmulator/SoftCPU.cpp16
1 files changed, 12 insertions, 4 deletions
diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp
index 46c6f69466..1928f56917 100644
--- a/DevTools/UserspaceEmulator/SoftCPU.cpp
+++ b/DevTools/UserspaceEmulator/SoftCPU.cpp
@@ -32,6 +32,14 @@
namespace UserspaceEmulator {
+template<typename T, typename U>
+inline constexpr T sign_extended_to(U value)
+{
+ if (!(value & X86::TypeTrivia<U>::sign_bit))
+ return value;
+ return (X86::TypeTrivia<T>::mask & ~X86::TypeTrivia<U>::mask) | value;
+}
+
template<typename T>
struct TypeDoubler {
};
@@ -443,7 +451,7 @@ template<bool update_dest, typename Op>
void SoftCPU::generic_RM16_imm8(Op op, const X86::Instruction& insn)
{
auto dest = insn.modrm().read16(*this, insn);
- auto src = insn.imm8();
+ auto src = sign_extended_to<u16>(insn.imm8());
auto result = op(*this, dest, src);
if (update_dest)
insn.modrm().write16(*this, insn, result);
@@ -473,7 +481,7 @@ template<bool update_dest, typename Op>
void SoftCPU::generic_RM32_imm8(Op op, const X86::Instruction& insn)
{
auto dest = insn.modrm().read32(*this, insn);
- auto src = insn.imm8();
+ auto src = sign_extended_to<u32>(insn.imm8());
auto result = op(*this, dest, src);
if (update_dest)
insn.modrm().write32(*this, insn, result);
@@ -1307,8 +1315,8 @@ void SoftCPU::XLAT(const X86::Instruction&) { TODO(); }
#define DEFINE_GENERIC_INSN_HANDLERS(mnemonic, op, update_dest) \
DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(mnemonic, op, update_dest) \
- void SoftCPU::mnemonic##_RM16_imm8(const X86::Instruction& insn) { generic_RM16_imm8<update_dest>(op<u16, u8>, insn); } \
- void SoftCPU::mnemonic##_RM32_imm8(const X86::Instruction& insn) { generic_RM32_imm8<update_dest>(op<u32, u8>, insn); } \
+ void SoftCPU::mnemonic##_RM16_imm8(const X86::Instruction& insn) { generic_RM16_imm8<update_dest>(op<u16, u16>, insn); } \
+ void SoftCPU::mnemonic##_RM32_imm8(const X86::Instruction& insn) { generic_RM32_imm8<update_dest>(op<u32, u32>, insn); } \
void SoftCPU::mnemonic##_reg16_RM16(const X86::Instruction& insn) { generic_reg16_RM16<update_dest>(op<u16, u16>, insn); } \
void SoftCPU::mnemonic##_reg32_RM32(const X86::Instruction& insn) { generic_reg32_RM32<update_dest>(op<u32, u32>, insn); } \
void SoftCPU::mnemonic##_reg8_RM8(const X86::Instruction& insn) { generic_reg8_RM8<update_dest>(op<u8, u8>, insn); }