Skip to content

Commit d592ed6

Browse files
committed
Add bswap, popcnt, clz, ctz, cls, and rbit instructions
1 parent 9987102 commit d592ed6

22 files changed

Lines changed: 714 additions & 11 deletions

binaryninjaapi.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15006,6 +15006,69 @@ namespace BinaryNinja {
1500615006
*/
1500715007
ExprId Not(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
1500815008

15009+
/*! Reverse the byte order of expression \c value of size \c size potentially setting flags
15010+
15011+
\param size The size of the result in bytes
15012+
\param a The expression to byte swap
15013+
\param flags Flags to set
15014+
\param loc Optional IL Location this expression was added from.
15015+
\return The expression <tt>bswap.<size>{<flags>}(value)</tt>
15016+
*/
15017+
ExprId ByteSwap(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
15018+
15019+
/*! Count the number of set bits in expression \c value of size \c size potentially setting flags
15020+
15021+
\param size The size of the result in bytes
15022+
\param a The expression to count set bits in
15023+
\param flags Flags to set
15024+
\param loc Optional IL Location this expression was added from.
15025+
\return The expression <tt>popcnt.<size>{<flags>}(value)</tt>
15026+
*/
15027+
ExprId PopulationCount(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
15028+
15029+
/*! Count the number of leading zero bits in expression \c value of size \c size potentially setting flags.
15030+
The result is <tt>8 * size</tt> when \c value is zero.
15031+
15032+
\param size The size of the result in bytes
15033+
\param a The expression to count leading zeros in
15034+
\param flags Flags to set
15035+
\param loc Optional IL Location this expression was added from.
15036+
\return The expression <tt>clz.<size>{<flags>}(value)</tt>
15037+
*/
15038+
ExprId CountLeadingZeros(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
15039+
15040+
/*! Count the number of trailing zero bits in expression \c value of size \c size potentially setting flags.
15041+
The result is <tt>8 * size</tt> when \c value is zero.
15042+
15043+
\param size The size of the result in bytes
15044+
\param a The expression to count trailing zeros in
15045+
\param flags Flags to set
15046+
\param loc Optional IL Location this expression was added from.
15047+
\return The expression <tt>ctz.<size>{<flags>}(value)</tt>
15048+
*/
15049+
ExprId CountTrailingZeros(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
15050+
15051+
/*! Reverse the bit order of expression \c value of size \c size potentially setting flags
15052+
15053+
\param size The size of the result in bytes
15054+
\param a The expression to bit reverse
15055+
\param flags Flags to set
15056+
\param loc Optional IL Location this expression was added from.
15057+
\return The expression <tt>rbit.<size>{<flags>}(value)</tt>
15058+
*/
15059+
ExprId ReverseBits(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
15060+
15061+
/*! Count the number of leading bits that match the sign bit in expression \c value of size \c size,
15062+
not counting the sign bit itself, potentially setting flags
15063+
15064+
\param size The size of the result in bytes
15065+
\param a The expression to count leading sign bits in
15066+
\param flags Flags to set
15067+
\param loc Optional IL Location this expression was added from.
15068+
\return The expression <tt>cls.<size>{<flags>}(value)</tt>
15069+
*/
15070+
ExprId CountLeadingSigns(size_t size, ExprId a, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
15071+
1500915072
/*! Two's complement sign-extends the expression in \c value to \c size bytes
1501015073

1501115074
\param size The size of the result in bytes
@@ -15886,6 +15949,12 @@ namespace BinaryNinja {
1588615949
size_t size, ExprId left, ExprId right, const ILSourceLocation& loc = ILSourceLocation());
1588715950
ExprId Neg(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1588815951
ExprId Not(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
15952+
ExprId ByteSwap(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
15953+
ExprId PopulationCount(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
15954+
ExprId CountLeadingZeros(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
15955+
ExprId CountTrailingZeros(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
15956+
ExprId ReverseBits(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
15957+
ExprId CountLeadingSigns(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1588915958
ExprId SignExtend(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1589015959
ExprId ZeroExtend(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1589115960
ExprId LowPart(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
@@ -16287,6 +16356,12 @@ namespace BinaryNinja {
1628716356
size_t size, ExprId left, ExprId right, const ILSourceLocation& loc = ILSourceLocation());
1628816357
ExprId Neg(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1628916358
ExprId Not(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
16359+
ExprId ByteSwap(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
16360+
ExprId PopulationCount(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
16361+
ExprId CountLeadingZeros(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
16362+
ExprId CountTrailingZeros(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
16363+
ExprId ReverseBits(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
16364+
ExprId CountLeadingSigns(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1629016365
ExprId SignExtend(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1629116366
ExprId ZeroExtend(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
1629216367
ExprId LowPart(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());

binaryninjacore.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,15 @@ extern "C"
762762
LLIL_REG_PHI,
763763
LLIL_REG_STACK_PHI,
764764
LLIL_FLAG_PHI,
765-
LLIL_MEM_PHI
765+
LLIL_MEM_PHI,
766+
767+
// Bit manipulation
768+
LLIL_BSWAP, // Reverse byte order of the whole value
769+
LLIL_POPCNT, // Population count (number of set bits)
770+
LLIL_CLZ, // Count leading zero bits; clz(0) == 8 * size
771+
LLIL_CTZ, // Count trailing zero bits; ctz(0) == 8 * size
772+
LLIL_RBIT, // Reverse bit order of the whole value
773+
LLIL_CLS // Count leading sign bits; number of bits below the sign bit that match it
766774
};
767775

768776
BN_ENUM(uint8_t, BNLowLevelILFlagCondition)
@@ -1540,7 +1548,15 @@ extern "C"
15401548
MLIL_VAR_PHI,
15411549
MLIL_MEM_PHI,
15421550

1543-
MLIL_BLOCK_TO_EXPAND // Must be expanded by a future workflow step, used temporarily to insert instructions
1551+
MLIL_BLOCK_TO_EXPAND, // Must be expanded by a future workflow step, used temporarily to insert instructions
1552+
1553+
// Bit manipulation
1554+
MLIL_BSWAP, // Reverse byte order of the whole value
1555+
MLIL_POPCNT, // Population count (number of set bits)
1556+
MLIL_CLZ, // Count leading zero bits; clz(0) == 8 * size
1557+
MLIL_CTZ, // Count trailing zero bits; ctz(0) == 8 * size
1558+
MLIL_RBIT, // Reverse bit order of the whole value
1559+
MLIL_CLS // Count leading sign bits; number of bits below the sign bit that match it
15441560
};
15451561

15461562
typedef struct BNMediumLevelILInstruction
@@ -1714,7 +1730,15 @@ extern "C"
17141730
HLIL_SYSCALL_SSA,
17151731
HLIL_INTRINSIC_SSA,
17161732
HLIL_VAR_PHI,
1717-
HLIL_MEM_PHI
1733+
HLIL_MEM_PHI,
1734+
1735+
// Bit manipulation
1736+
HLIL_BSWAP, // Reverse byte order of the whole value
1737+
HLIL_POPCNT, // Population count (number of set bits)
1738+
HLIL_CLZ, // Count leading zero bits; clz(0) == 8 * size
1739+
HLIL_CTZ, // Count trailing zero bits; ctz(0) == 8 * size
1740+
HLIL_RBIT, // Reverse bit order of the whole value
1741+
HLIL_CLS // Count leading sign bits; number of bits below the sign bit that match it
17181742
};
17191743

17201744
typedef struct BNHighLevelILInstruction

docs/dev/bnil-hlil.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ There are a number of properties that can be queried on the [`HighLevelILInstruc
111111
* `HLIL_MODS_DP` - Signed double-precision modulus of `left` expression by the `right` expression
112112
* `HLIL_NEG` - Sign inversion of `src` expression
113113
* `HLIL_NOT` - Bitwise inversion of `src` expression
114+
* `HLIL_BSWAP` - Reverse the byte order of `src` expression
115+
* `HLIL_POPCNT` - Population count (number of set bits) of `src` expression
116+
* `HLIL_CLZ` - Count leading zero bits of `src` expression; the result is `8 * size` when `src` is zero
117+
* `HLIL_CTZ` - Count trailing zero bits of `src` expression; the result is `8 * size` when `src` is zero
118+
* `HLIL_RBIT` - Reverse the bit order of `src` expression
119+
* `HLIL_CLS` - Count leading sign bits of `src` expression (the number of bits below the sign bit that match it)
114120
* `HLIL_FADD` - IEEE754 floating point addition of `left` expression with `right` expression
115121
* `HLIL_FSUB` - IEEE754 floating point subtraction of `left` expression with `right` expression
116122
* `HLIL_FMUL` - IEEE754 floating point multiplication of `left` expression with `right` expression

docs/dev/bnil-llil.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ The double precision instruction multiply, divide, modulus instructions are part
257257
* `LLIL_MODS_DP` - Signed modulus double precision
258258
* `LLIL_NEG` - Sign negation
259259
* `LLIL_NOT` - Bitwise complement
260+
* `LLIL_BSWAP` - Reverse the byte order of `src`
261+
* `LLIL_POPCNT` - Population count (number of set bits) of `src`
262+
* `LLIL_CLZ` - Count leading zero bits of `src`; the result is `8 * size` when `src` is zero
263+
* `LLIL_CTZ` - Count trailing zero bits of `src`; the result is `8 * size` when `src` is zero
264+
* `LLIL_RBIT` - Reverse the bit order of `src`
265+
* `LLIL_CLS` - Count leading sign bits of `src` (the number of bits below the sign bit that match it)
260266
* `LLIL_TEST_BIT ` - Test if bit `right` in expression `left` is set
261267
* `LLIL_BOOL_TO_INT ` - Converts a bool `src` to an integer
262268

docs/dev/bnil-mlil.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ The parameter list can be accessed through the `params` property:
348348
* `MLIL_MODS_DP` - Signed double-precision modulus of `left` expression by the `right` expression
349349
* `MLIL_NEG` - Sign inversion of `src` expression
350350
* `MLIL_NOT` - Bitwise inversion of `src` expression
351+
* `MLIL_BSWAP` - Reverse the byte order of `src` expression
352+
* `MLIL_POPCNT` - Population count (number of set bits) of `src` expression
353+
* `MLIL_CLZ` - Count leading zero bits of `src` expression; the result is `8 * size` when `src` is zero
354+
* `MLIL_CTZ` - Count trailing zero bits of `src` expression; the result is `8 * size` when `src` is zero
355+
* `MLIL_RBIT` - Reverse the bit order of `src` expression
356+
* `MLIL_CLS` - Count leading sign bits of `src` expression (the number of bits below the sign bit that match it)
351357
* `MLIL_FADD` - IEEE754 floating point addition of `left` expression with `right` expression
352358
* `MLIL_FSUB` - IEEE754 floating point subtraction of `left` expression with `right` expression
353359
* `MLIL_FMUL` - IEEE754 floating point multiplication of `left` expression with `right` expression

highlevelilinstruction.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ static constexpr std::array s_instructionOperandUsage = {
260260
OperandUsage{HLIL_INTRINSIC_SSA, {IntrinsicHighLevelOperandUsage, ParameterExprsHighLevelOperandUsage, DestMemoryVersionHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}},
261261
OperandUsage{HLIL_VAR_PHI, {DestSSAVariableHighLevelOperandUsage, SourceSSAVariablesHighLevelOperandUsage}},
262262
OperandUsage{HLIL_MEM_PHI, {DestMemoryVersionHighLevelOperandUsage, SourceMemoryVersionsHighLevelOperandUsage}},
263+
OperandUsage{HLIL_BSWAP, {SourceExprHighLevelOperandUsage}},
264+
OperandUsage{HLIL_POPCNT, {SourceExprHighLevelOperandUsage}},
265+
OperandUsage{HLIL_CLZ, {SourceExprHighLevelOperandUsage}},
266+
OperandUsage{HLIL_CTZ, {SourceExprHighLevelOperandUsage}},
267+
OperandUsage{HLIL_RBIT, {SourceExprHighLevelOperandUsage}},
268+
OperandUsage{HLIL_CLS, {SourceExprHighLevelOperandUsage}},
263269
};
264270

265271

@@ -1261,6 +1267,12 @@ void HighLevelILInstruction::CollectSubExprs(stack<size_t>& toProcess) const
12611267
case HLIL_ADDRESS_OF:
12621268
case HLIL_NEG:
12631269
case HLIL_NOT:
1270+
case HLIL_BSWAP:
1271+
case HLIL_POPCNT:
1272+
case HLIL_CLZ:
1273+
case HLIL_CTZ:
1274+
case HLIL_RBIT:
1275+
case HLIL_CLS:
12641276
case HLIL_SX:
12651277
case HLIL_ZX:
12661278
case HLIL_LOW_PART:
@@ -1569,6 +1581,12 @@ ExprId HighLevelILInstruction::CopyTo(
15691581
return dest->Unreachable(loc);
15701582
case HLIL_NEG:
15711583
case HLIL_NOT:
1584+
case HLIL_BSWAP:
1585+
case HLIL_POPCNT:
1586+
case HLIL_CLZ:
1587+
case HLIL_CTZ:
1588+
case HLIL_RBIT:
1589+
case HLIL_CLS:
15721590
case HLIL_SX:
15731591
case HLIL_ZX:
15741592
case HLIL_LOW_PART:
@@ -2130,6 +2148,12 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons
21302148
case HLIL_DEREF:
21312149
case HLIL_NEG:
21322150
case HLIL_NOT:
2151+
case HLIL_BSWAP:
2152+
case HLIL_POPCNT:
2153+
case HLIL_CLZ:
2154+
case HLIL_CTZ:
2155+
case HLIL_RBIT:
2156+
case HLIL_CLS:
21332157
case HLIL_SX:
21342158
case HLIL_ZX:
21352159
case HLIL_LOW_PART:
@@ -3097,6 +3121,42 @@ ExprId HighLevelILFunction::Not(size_t size, ExprId src, const ILSourceLocation&
30973121
}
30983122

30993123

3124+
ExprId HighLevelILFunction::ByteSwap(size_t size, ExprId src, const ILSourceLocation& loc)
3125+
{
3126+
return AddExprWithLocation(HLIL_BSWAP, loc, size, src);
3127+
}
3128+
3129+
3130+
ExprId HighLevelILFunction::PopulationCount(size_t size, ExprId src, const ILSourceLocation& loc)
3131+
{
3132+
return AddExprWithLocation(HLIL_POPCNT, loc, size, src);
3133+
}
3134+
3135+
3136+
ExprId HighLevelILFunction::CountLeadingZeros(size_t size, ExprId src, const ILSourceLocation& loc)
3137+
{
3138+
return AddExprWithLocation(HLIL_CLZ, loc, size, src);
3139+
}
3140+
3141+
3142+
ExprId HighLevelILFunction::CountTrailingZeros(size_t size, ExprId src, const ILSourceLocation& loc)
3143+
{
3144+
return AddExprWithLocation(HLIL_CTZ, loc, size, src);
3145+
}
3146+
3147+
3148+
ExprId HighLevelILFunction::ReverseBits(size_t size, ExprId src, const ILSourceLocation& loc)
3149+
{
3150+
return AddExprWithLocation(HLIL_RBIT, loc, size, src);
3151+
}
3152+
3153+
3154+
ExprId HighLevelILFunction::CountLeadingSigns(size_t size, ExprId src, const ILSourceLocation& loc)
3155+
{
3156+
return AddExprWithLocation(HLIL_CLS, loc, size, src);
3157+
}
3158+
3159+
31003160
ExprId HighLevelILFunction::SignExtend(size_t size, ExprId src, const ILSourceLocation& loc)
31013161
{
31023162
return AddExprWithLocation(HLIL_SX, loc, size, src);

highlevelilinstruction.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,24 @@ namespace BinaryNinja
14541454
struct HighLevelILInstructionAccessor<HLIL_NOT> : public HighLevelILOneOperandInstruction
14551455
{};
14561456
template <>
1457+
struct HighLevelILInstructionAccessor<HLIL_BSWAP> : public HighLevelILOneOperandInstruction
1458+
{};
1459+
template <>
1460+
struct HighLevelILInstructionAccessor<HLIL_POPCNT> : public HighLevelILOneOperandInstruction
1461+
{};
1462+
template <>
1463+
struct HighLevelILInstructionAccessor<HLIL_CLZ> : public HighLevelILOneOperandInstruction
1464+
{};
1465+
template <>
1466+
struct HighLevelILInstructionAccessor<HLIL_CTZ> : public HighLevelILOneOperandInstruction
1467+
{};
1468+
template <>
1469+
struct HighLevelILInstructionAccessor<HLIL_RBIT> : public HighLevelILOneOperandInstruction
1470+
{};
1471+
template <>
1472+
struct HighLevelILInstructionAccessor<HLIL_CLS> : public HighLevelILOneOperandInstruction
1473+
{};
1474+
template <>
14571475
struct HighLevelILInstructionAccessor<HLIL_SX> : public HighLevelILOneOperandInstruction
14581476
{};
14591477
template <>

lang/c/pseudoc.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,85 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
24112411
}();
24122412
break;
24132413

2414+
case HLIL_BSWAP:
2415+
[&]() {
2416+
auto src = instr.GetSourceExpr<HLIL_BSWAP>();
2417+
string name;
2418+
if (src.size == 2)
2419+
name = "__builtin_bswap16";
2420+
else if (src.size == 4)
2421+
name = "__builtin_bswap32";
2422+
else if (src.size == 8)
2423+
name = "__builtin_bswap64";
2424+
else
2425+
name = "__builtin_bswap";
2426+
tokens.Append(OperationToken, name);
2427+
tokens.AppendOpenParen();
2428+
GetExprTextInternal(src, tokens, settings);
2429+
tokens.AppendCloseParen();
2430+
if (statement)
2431+
tokens.AppendSemicolon();
2432+
}();
2433+
break;
2434+
2435+
case HLIL_POPCNT:
2436+
[&]() {
2437+
auto src = instr.GetSourceExpr<HLIL_POPCNT>();
2438+
tokens.Append(OperationToken, src.size > 4 ? "__builtin_popcountll" : "__builtin_popcount");
2439+
tokens.AppendOpenParen();
2440+
GetExprTextInternal(src, tokens, settings);
2441+
tokens.AppendCloseParen();
2442+
if (statement)
2443+
tokens.AppendSemicolon();
2444+
}();
2445+
break;
2446+
2447+
case HLIL_CLZ:
2448+
[&]() {
2449+
auto src = instr.GetSourceExpr<HLIL_CLZ>();
2450+
tokens.Append(OperationToken, src.size > 4 ? "__builtin_clzll" : "__builtin_clz");
2451+
tokens.AppendOpenParen();
2452+
GetExprTextInternal(src, tokens, settings);
2453+
tokens.AppendCloseParen();
2454+
if (statement)
2455+
tokens.AppendSemicolon();
2456+
}();
2457+
break;
2458+
2459+
case HLIL_CTZ:
2460+
[&]() {
2461+
auto src = instr.GetSourceExpr<HLIL_CTZ>();
2462+
tokens.Append(OperationToken, src.size > 4 ? "__builtin_ctzll" : "__builtin_ctz");
2463+
tokens.AppendOpenParen();
2464+
GetExprTextInternal(src, tokens, settings);
2465+
tokens.AppendCloseParen();
2466+
if (statement)
2467+
tokens.AppendSemicolon();
2468+
}();
2469+
break;
2470+
2471+
case HLIL_RBIT:
2472+
[&]() {
2473+
tokens.Append(OperationToken, "__rbit");
2474+
tokens.AppendOpenParen();
2475+
GetExprTextInternal(instr.GetSourceExpr<HLIL_RBIT>(), tokens, settings);
2476+
tokens.AppendCloseParen();
2477+
if (statement)
2478+
tokens.AppendSemicolon();
2479+
}();
2480+
break;
2481+
2482+
case HLIL_CLS:
2483+
[&]() {
2484+
tokens.Append(OperationToken, "__cls");
2485+
tokens.AppendOpenParen();
2486+
GetExprTextInternal(instr.GetSourceExpr<HLIL_CLS>(), tokens, settings);
2487+
tokens.AppendCloseParen();
2488+
if (statement)
2489+
tokens.AppendSemicolon();
2490+
}();
2491+
break;
2492+
24142493
case HLIL_FLOAT_CONV:
24152494
[&]() {
24162495
const auto srcExpr = instr.GetSourceExpr<HLIL_FLOAT_CONV>();

0 commit comments

Comments
 (0)