diff --git a/tests/src/tests/tests.decoder.cpp b/tests/src/tests/tests.decoder.cpp index 22cafb7..c1e22d1 100644 --- a/tests/src/tests/tests.decoder.cpp +++ b/tests/src/tests/tests.decoder.cpp @@ -78,4 +78,48 @@ namespace zasm::tests } } + TEST(DecoderTests, Issue_149) + { + Program program(MachineMode::AMD64); + Decoder decoder(MachineMode::AMD64); + + const std::array inputBytes = { + 0xF0, 0x0F, 0xB1, 0x95, 0x74, 0x17, 0x01, 0x00, // lock cmpxchg dword ptr ss:[rbp+0x11774], edx + }; + + auto decoded = decoder.decode(inputBytes.data(), inputBytes.size(), 0x00400000); + ASSERT_TRUE(decoded); + + ASSERT_EQ(decoded->getMnemonic(), x86::Mnemonic::Cmpxchg); + + ASSERT_EQ(decoded->getOperandCount(), 4); + + ASSERT_EQ(decoded->isOperandType(0), true); + ASSERT_EQ(decoded->getOperand(0).getBase(), x86::rbp); + ASSERT_EQ(decoded->getOperand(0).getDisplacement(), 0x11774); + ASSERT_EQ(decoded->isOperandRead(0), true); + ASSERT_EQ(decoded->isOperandWrite(0), true); + ASSERT_EQ(decoded->isOperandCondWrite(0), true); + + ASSERT_EQ(decoded->isOperandType(1), true); + ASSERT_EQ(decoded->getOperand(1), x86::edx); + ASSERT_EQ(decoded->isOperandRead(1), true); + ASSERT_EQ(decoded->isOperandCondRead(1), false); + ASSERT_EQ(decoded->isOperandWrite(1), false); + ASSERT_EQ(decoded->isOperandCondWrite(1), false); + + ASSERT_EQ(decoded->isOperandType(2), true); + ASSERT_EQ(decoded->getOperand(2), x86::eax); + ASSERT_EQ(decoded->isOperandRead(2), true); + ASSERT_EQ(decoded->isOperandWrite(2), true); + ASSERT_EQ(decoded->isOperandCondWrite(2), true); + + ASSERT_EQ(decoded->isOperandType(3), true); + ASSERT_EQ(decoded->getOperand(3), x86::rflags); + ASSERT_EQ(decoded->isOperandRead(3), false); + ASSERT_EQ(decoded->isOperandCondRead(3), false); + ASSERT_EQ(decoded->isOperandWrite(3), true); + ASSERT_EQ(decoded->isOperandCondWrite(3), false); + } + } // namespace zasm::tests diff --git a/tests/src/tests/tests.packed.cpp b/tests/src/tests/tests.packed.cpp index 46d4424..4c0d91f 100644 --- a/tests/src/tests/tests.packed.cpp +++ b/tests/src/tests/tests.packed.cpp @@ -81,4 +81,49 @@ namespace zasm::tests ASSERT_EQ(vis.get<8>(), Operand::Visibility::Invalid); ASSERT_EQ(vis.get<9>(), Operand::Visibility::Invalid); } -} // namespace zasm::tests + + TEST(PackedTests, TestPackOperandAccess) + { + using PackedOperandAccess = Packed; + static_assert(sizeof(PackedOperandAccess) == sizeof(uint64_t)); + + PackedOperandAccess access{}; + ASSERT_EQ(access.size(), 16); + ASSERT_EQ(access.capacity(), 16); + + ASSERT_EQ(access.get<0>(), Operand::Access::None); + ASSERT_EQ(access.get<1>(), Operand::Access::None); + ASSERT_EQ(access.get<2>(), Operand::Access::None); + ASSERT_EQ(access.get<3>(), Operand::Access::None); + ASSERT_EQ(access.get<4>(), Operand::Access::None); + ASSERT_EQ(access.get<5>(), Operand::Access::None); + ASSERT_EQ(access.get<6>(), Operand::Access::None); + ASSERT_EQ(access.get<7>(), Operand::Access::None); + ASSERT_EQ(access.get<8>(), Operand::Access::None); + ASSERT_EQ(access.get<9>(), Operand::Access::None); + ASSERT_EQ(access.get<10>(), Operand::Access::None); + + access.set<0>(Operand::Access::Read); + ASSERT_EQ(access.get<0>(), Operand::Access::Read); + + access.set<5>(Operand::Access::Write); + ASSERT_EQ(access.get<0>(), Operand::Access::Read); + ASSERT_EQ(access.get<5>(), Operand::Access::Write); + + access.set<10>(Operand::Access::CondRead); + ASSERT_EQ(access.get<0>(), Operand::Access::Read); + + access.set<15>(Operand::Access::CondWrite); + ASSERT_EQ(access.get<0>(), Operand::Access::Read); + ASSERT_EQ(access.get<5>(), Operand::Access::Write); + ASSERT_EQ(access.get<10>(), Operand::Access::CondRead); + ASSERT_EQ(access.get<15>(), Operand::Access::CondWrite); + + access.set<15>(Operand::Access::None); + ASSERT_EQ(access.get<0>(), Operand::Access::Read); + ASSERT_EQ(access.get<5>(), Operand::Access::Write); + ASSERT_EQ(access.get<10>(), Operand::Access::CondRead); + ASSERT_EQ(access.get<15>(), Operand::Access::None); + } + + } // namespace zasm::tests diff --git a/zasm/include/zasm/core/packed.hpp b/zasm/include/zasm/core/packed.hpp index 44f1d45..34f9a44 100644 --- a/zasm/include/zasm/core/packed.hpp +++ b/zasm/include/zasm/core/packed.hpp @@ -54,7 +54,7 @@ namespace zasm template constexpr void set(const TElement& val) noexcept { constexpr auto bitIndex = (TIndex * TElementBitSize); - static_assert(bitIndex + TElementBitSize < kStorageBitSize); + static_assert(bitIndex + TElementBitSize <= kStorageBitSize); const auto newVal = (static_cast(val) & kElementMask) << bitIndex; @@ -81,7 +81,7 @@ namespace zasm template constexpr TElement get() const noexcept { constexpr auto bitIndex = (TIndex * TElementBitSize); - static_assert(bitIndex + TElementBitSize < kStorageBitSize); + static_assert(bitIndex + TElementBitSize <= kStorageBitSize); const auto res = (_data >> bitIndex) & kElementMask; return static_cast(res); diff --git a/zasm/include/zasm/program/instruction.hpp b/zasm/include/zasm/program/instruction.hpp index ed861c2..e393ca4 100644 --- a/zasm/include/zasm/program/instruction.hpp +++ b/zasm/include/zasm/program/instruction.hpp @@ -67,7 +67,7 @@ namespace zasm public: static constexpr auto kInstrType = InstructionBase::Type::Detail; - using OperandsAccess = Packed; + using OperandsAccess = Packed; using OperandsVisibility = Packed; struct CPUFlags