Skip to content

Commit 2e6f68f

Browse files
xusheng6claude
andcommitted
[emulator] Fix RLC/RRC rotate-through-carry semantics
The rotate-through-carry implementations mixed a pre-shifted value with an un-rotated operand (RLC) and dropped the low bits instead of wrapping them (RRC), producing wrong results (e.g. 1-byte RLC(0x80, carry=0, count=1) gave 0x01 instead of 0x00). Implement both as a true rotate of the (bits+1)-bit {carry:value} quantity, and record m_lastArithmetic like ROL/ROR so a later flag read is not stale. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 2d427a7 commit 2e6f68f

1 file changed

Lines changed: 17 additions & 5 deletions

File tree

plugins/emulator/core/llilemulator.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,24 +1110,36 @@ intx::uint512 LLILEmulator::EvalExpr(const LowLevelILInstruction& expr)
11101110

11111111
case LLIL_RLC:
11121112
{
1113+
// Rotate left through carry: rotate the (bits + 1)-bit quantity {carry : value},
1114+
// with carry as the most-significant bit.
11131115
intx::uint512 left = MaskToSize(EvalExpr(expr.GetRawOperandAsExpr(0)), sz);
11141116
intx::uint512 right = EvalExpr(expr.GetRawOperandAsExpr(1));
11151117
intx::uint512 carry = EvalExpr(expr.GetRawOperandAsExpr(2)) & 1;
11161118
size_t bits = sz * 8;
1117-
size_t shift = static_cast<size_t>(static_cast<uint64_t>(right) % (bits + 1));
1118-
intx::uint512 extended = (left << 1) | carry;
1119-
return MaskToSize((extended << shift) | (left >> (bits - shift)), sz);
1119+
size_t width = bits + 1;
1120+
size_t shift = static_cast<size_t>(static_cast<uint64_t>(right) % width);
1121+
intx::uint512 extended = left | (carry << bits);
1122+
intx::uint512 rotated = (shift == 0) ? extended : ((extended << shift) | (extended >> (width - shift)));
1123+
intx::uint512 result = MaskToSize(rotated, sz);
1124+
m_lastArithmetic = {left, right, result, sz, LLIL_RLC, true};
1125+
return result;
11201126
}
11211127

11221128
case LLIL_RRC:
11231129
{
1130+
// Rotate right through carry: rotate the (bits + 1)-bit quantity {carry : value},
1131+
// with carry as the most-significant bit.
11241132
intx::uint512 left = MaskToSize(EvalExpr(expr.GetRawOperandAsExpr(0)), sz);
11251133
intx::uint512 right = EvalExpr(expr.GetRawOperandAsExpr(1));
11261134
intx::uint512 carry = EvalExpr(expr.GetRawOperandAsExpr(2)) & 1;
11271135
size_t bits = sz * 8;
1128-
size_t shift = static_cast<size_t>(static_cast<uint64_t>(right) % (bits + 1));
1136+
size_t width = bits + 1;
1137+
size_t shift = static_cast<size_t>(static_cast<uint64_t>(right) % width);
11291138
intx::uint512 extended = left | (carry << bits);
1130-
return MaskToSize(extended >> shift, sz);
1139+
intx::uint512 rotated = (shift == 0) ? extended : ((extended >> shift) | (extended << (width - shift)));
1140+
intx::uint512 result = MaskToSize(rotated, sz);
1141+
m_lastArithmetic = {left, right, result, sz, LLIL_RRC, true};
1142+
return result;
11311143
}
11321144

11331145
// --- Division ---

0 commit comments

Comments
 (0)