Skip to content

Commit 07c0bdb

Browse files
committed
Fix operand access being wrong about conditional access
1 parent e7d80fb commit 07c0bdb

File tree

4 files changed

+93
-4
lines changed

4 files changed

+93
-4
lines changed

tests/src/tests/tests.decoder.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,48 @@ namespace zasm::tests
7878
}
7979
}
8080

81+
TEST(DecoderTests, Issue_149)
82+
{
83+
Program program(MachineMode::AMD64);
84+
Decoder decoder(MachineMode::AMD64);
85+
86+
const std::array<uint8_t, 8> inputBytes = {
87+
0xF0, 0x0F, 0xB1, 0x95, 0x74, 0x17, 0x01, 0x00, // lock cmpxchg dword ptr ss:[rbp+0x11774], edx
88+
};
89+
90+
auto decoded = decoder.decode(inputBytes.data(), inputBytes.size(), 0x00400000);
91+
ASSERT_TRUE(decoded);
92+
93+
ASSERT_EQ(decoded->getMnemonic(), x86::Mnemonic::Cmpxchg);
94+
95+
ASSERT_EQ(decoded->getOperandCount(), 4);
96+
97+
ASSERT_EQ(decoded->isOperandType<Mem>(0), true);
98+
ASSERT_EQ(decoded->getOperand<Mem>(0).getBase(), x86::rbp);
99+
ASSERT_EQ(decoded->getOperand<Mem>(0).getDisplacement(), 0x11774);
100+
ASSERT_EQ(decoded->isOperandRead(0), true);
101+
ASSERT_EQ(decoded->isOperandWrite(0), true);
102+
ASSERT_EQ(decoded->isOperandCondWrite(0), true);
103+
104+
ASSERT_EQ(decoded->isOperandType<Reg>(1), true);
105+
ASSERT_EQ(decoded->getOperand<Reg>(1), x86::edx);
106+
ASSERT_EQ(decoded->isOperandRead(1), true);
107+
ASSERT_EQ(decoded->isOperandCondRead(1), false);
108+
ASSERT_EQ(decoded->isOperandWrite(1), false);
109+
ASSERT_EQ(decoded->isOperandCondWrite(1), false);
110+
111+
ASSERT_EQ(decoded->isOperandType<Reg>(2), true);
112+
ASSERT_EQ(decoded->getOperand<Reg>(2), x86::eax);
113+
ASSERT_EQ(decoded->isOperandRead(2), true);
114+
ASSERT_EQ(decoded->isOperandWrite(2), true);
115+
ASSERT_EQ(decoded->isOperandCondWrite(2), true);
116+
117+
ASSERT_EQ(decoded->isOperandType<Reg>(3), true);
118+
ASSERT_EQ(decoded->getOperand<Reg>(3), x86::rflags);
119+
ASSERT_EQ(decoded->isOperandRead(3), false);
120+
ASSERT_EQ(decoded->isOperandCondRead(3), false);
121+
ASSERT_EQ(decoded->isOperandWrite(3), true);
122+
ASSERT_EQ(decoded->isOperandCondWrite(3), false);
123+
}
124+
81125
} // namespace zasm::tests

tests/src/tests/tests.packed.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,49 @@ namespace zasm::tests
8181
ASSERT_EQ(vis.get<8>(), Operand::Visibility::Invalid);
8282
ASSERT_EQ(vis.get<9>(), Operand::Visibility::Invalid);
8383
}
84-
} // namespace zasm::tests
84+
85+
TEST(PackedTests, TestPackOperandAccess)
86+
{
87+
using PackedOperandAccess = Packed<uint64_t, Operand::Access, 4>;
88+
static_assert(sizeof(PackedOperandAccess) == sizeof(uint64_t));
89+
90+
PackedOperandAccess access{};
91+
ASSERT_EQ(access.size(), 16);
92+
ASSERT_EQ(access.capacity(), 16);
93+
94+
ASSERT_EQ(access.get<0>(), Operand::Access::None);
95+
ASSERT_EQ(access.get<1>(), Operand::Access::None);
96+
ASSERT_EQ(access.get<2>(), Operand::Access::None);
97+
ASSERT_EQ(access.get<3>(), Operand::Access::None);
98+
ASSERT_EQ(access.get<4>(), Operand::Access::None);
99+
ASSERT_EQ(access.get<5>(), Operand::Access::None);
100+
ASSERT_EQ(access.get<6>(), Operand::Access::None);
101+
ASSERT_EQ(access.get<7>(), Operand::Access::None);
102+
ASSERT_EQ(access.get<8>(), Operand::Access::None);
103+
ASSERT_EQ(access.get<9>(), Operand::Access::None);
104+
ASSERT_EQ(access.get<10>(), Operand::Access::None);
105+
106+
access.set<0>(Operand::Access::Read);
107+
ASSERT_EQ(access.get<0>(), Operand::Access::Read);
108+
109+
access.set<5>(Operand::Access::Write);
110+
ASSERT_EQ(access.get<0>(), Operand::Access::Read);
111+
ASSERT_EQ(access.get<5>(), Operand::Access::Write);
112+
113+
access.set<10>(Operand::Access::CondRead);
114+
ASSERT_EQ(access.get<0>(), Operand::Access::Read);
115+
116+
access.set<15>(Operand::Access::CondWrite);
117+
ASSERT_EQ(access.get<0>(), Operand::Access::Read);
118+
ASSERT_EQ(access.get<5>(), Operand::Access::Write);
119+
ASSERT_EQ(access.get<10>(), Operand::Access::CondRead);
120+
ASSERT_EQ(access.get<15>(), Operand::Access::CondWrite);
121+
122+
access.set<15>(Operand::Access::None);
123+
ASSERT_EQ(access.get<0>(), Operand::Access::Read);
124+
ASSERT_EQ(access.get<5>(), Operand::Access::Write);
125+
ASSERT_EQ(access.get<10>(), Operand::Access::CondRead);
126+
ASSERT_EQ(access.get<15>(), Operand::Access::None);
127+
}
128+
129+
} // namespace zasm::tests

zasm/include/zasm/core/packed.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ namespace zasm
5454
template<std::size_t TIndex> constexpr void set(const TElement& val) noexcept
5555
{
5656
constexpr auto bitIndex = (TIndex * TElementBitSize);
57-
static_assert(bitIndex + TElementBitSize < kStorageBitSize);
57+
static_assert(bitIndex + TElementBitSize <= kStorageBitSize);
5858

5959
const auto newVal = (static_cast<TUnderlying>(val) & kElementMask) << bitIndex;
6060

@@ -81,7 +81,7 @@ namespace zasm
8181
template<std::size_t TIndex> constexpr TElement get() const noexcept
8282
{
8383
constexpr auto bitIndex = (TIndex * TElementBitSize);
84-
static_assert(bitIndex + TElementBitSize < kStorageBitSize);
84+
static_assert(bitIndex + TElementBitSize <= kStorageBitSize);
8585

8686
const auto res = (_data >> bitIndex) & kElementMask;
8787
return static_cast<TElement>(res);

zasm/include/zasm/program/instruction.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ namespace zasm
6767
public:
6868
static constexpr auto kInstrType = InstructionBase::Type::Detail;
6969

70-
using OperandsAccess = Packed<std::uint32_t, Operand::Access, 3>;
70+
using OperandsAccess = Packed<std::uint64_t, Operand::Access, 4>;
7171
using OperandsVisibility = Packed<std::uint32_t, Operand::Visibility, 3>;
7272

7373
struct CPUFlags

0 commit comments

Comments
 (0)