Skip to content

Commit bbcf12d

Browse files
committed
[x86] Lift BEXTR with concise intrinsics and correct flags
Use __bextr32 and __bextr64 with named value, start, and length parameters to keep decompilation compact for both constant and variable controls. Use the flag system to set ZF from the result, clear CF/OF, and model AF/SF/PF as unknown. Separate ZF updates to prevent SF from being incorrectly inferred from the result. Preserve APX flag suppression.
1 parent 5a6196f commit bbcf12d

4 files changed

Lines changed: 61 additions & 2 deletions

File tree

‎arch/x86/arch_x86.cpp‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2137,6 +2137,22 @@ size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, s
21372137
il.Const(size, 0));
21382138
}
21392139

2140+
if (flagWriteType == IL_FLAGWRITE_BEXTR)
2141+
{
2142+
switch (flag)
2143+
{
2144+
case IL_FLAG_C:
2145+
case IL_FLAG_O:
2146+
return il.Const(0, 0);
2147+
case IL_FLAG_A:
2148+
case IL_FLAG_S:
2149+
case IL_FLAG_P:
2150+
return il.Unknown();
2151+
default:
2152+
break;
2153+
}
2154+
}
2155+
21402156
if (flagWriteType == IL_FLAGWRITE_PTEST)
21412157
{
21422158
switch (flag)
@@ -2935,6 +2951,10 @@ string X86CommonArchitecture::GetFlagWriteTypeName(uint32_t flags)
29352951
return "cuo";
29362952
case IL_FLAGWRITE_PTEST:
29372953
return "ptest";
2954+
case IL_FLAGWRITE_BEXTR:
2955+
return "bextr";
2956+
case IL_FLAGWRITE_Z:
2957+
return "z";
29382958
default:
29392959
return "";
29402960
}
@@ -2962,7 +2982,7 @@ vector<uint32_t> X86CommonArchitecture::GetAllFlagWriteTypes()
29622982
return vector<uint32_t> {IL_FLAGWRITE_ALL, IL_FLAGWRITE_NOCARRY, IL_FLAGWRITE_CO,
29632983
IL_FLAGWRITE_X87COM, IL_FLAGWRITE_X87COMI, IL_FLAGWRITE_X87C1Z, IL_FLAGWRITE_X87RND,
29642984
IL_FLAGWRITE_VCOMI, IL_FLAGWRITE_POPCNT, IL_FLAGWRITE_LZTZCNT, IL_FLAGWRITE_PAZS,
2965-
IL_FLAGWRITE_C, IL_FLAGWRITE_SHRD1, IL_FLAGWRITE_CUO, IL_FLAGWRITE_PTEST};
2985+
IL_FLAGWRITE_C, IL_FLAGWRITE_SHRD1, IL_FLAGWRITE_CUO, IL_FLAGWRITE_PTEST, IL_FLAGWRITE_BEXTR, IL_FLAGWRITE_Z};
29662986
}
29672987

29682988
BNFlagRole X86CommonArchitecture::GetFlagRole(uint32_t flag, uint32_t semClass)
@@ -3190,6 +3210,10 @@ vector<uint32_t> X86CommonArchitecture::GetFlagsWrittenByFlagWriteType(uint32_t
31903210
return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_O };
31913211
case IL_FLAGWRITE_PTEST:
31923212
return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O };
3213+
case IL_FLAGWRITE_BEXTR:
3214+
return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_S, IL_FLAG_O };
3215+
case IL_FLAGWRITE_Z:
3216+
return vector<uint32_t>{ IL_FLAG_Z };
31933217
default:
31943218
return vector<uint32_t>();
31953219
}

‎arch/x86/arch_x86_intrinsics.cpp‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ string X86CommonArchitecture::GetIntrinsicName(uint32_t intrinsic)
3737
{
3838
case INTRINSIC_F2XM1:
3939
return "__f2xm1";
40+
case INTRINSIC_BEXTR32:
41+
return "__bextr32";
42+
case INTRINSIC_BEXTR64:
43+
return "__bextr64";
4044
case INTRINSIC_FBLD:
4145
return "__fbld";
4246
case INTRINSIC_FBST:
@@ -5112,7 +5116,7 @@ vector<uint32_t> X86CommonArchitecture::GetAllIntrinsics()
51125116
vector<uint32_t> allIntrinsics = { INTRINSIC_F2XM1, INTRINSIC_FBLD, INTRINSIC_FBST , INTRINSIC_FSIN,
51135117
INTRINSIC_FCOS, INTRINSIC_FSINCOS, INTRINSIC_FPATAN, INTRINSIC_FPREM, INTRINSIC_FPREM1,
51145118
INTRINSIC_FPTAN, INTRINSIC_FSCALE, INTRINSIC_FXAM, INTRINSIC_FXTRACT, INTRINSIC_FYL2X,
5115-
INTRINSIC_FYL2XP1};
5119+
INTRINSIC_FYL2XP1, INTRINSIC_BEXTR32, INTRINSIC_BEXTR64};
51165120

51175121
allIntrinsics.reserve(allIntrinsics.size() + INTRINSIC_LAST - INTRINSIC_XED_IFORM_INVALID + 1);
51185122
for (uint32_t value = INTRINSIC_XED_IFORM_INVALID;
@@ -5134,6 +5138,12 @@ vector<NameAndType> X86CommonArchitecture::GetIntrinsicInputs(uint32_t intrinsic
51345138

51355139
switch (intrinsic)
51365140
{
5141+
case INTRINSIC_BEXTR32:
5142+
case INTRINSIC_BEXTR64:
5143+
return {
5144+
NameAndType("value", Type::IntegerType(intrinsic == INTRINSIC_BEXTR64 ? 8 : 4, false)),
5145+
NameAndType("start", Type::IntegerType(1, false)),
5146+
NameAndType("length", Type::IntegerType(1, false))};
51375147
case INTRINSIC_F2XM1:
51385148
case INTRINSIC_FBST:
51395149
case INTRINSIC_FSIN:
@@ -5196,6 +5206,10 @@ vector<Confidence<Ref<Type>>> X86CommonArchitecture::GetIntrinsicOutputs(uint32_
51965206

51975207
switch (intrinsic)
51985208
{
5209+
case INTRINSIC_BEXTR32:
5210+
return {Type::IntegerType(4, false)};
5211+
case INTRINSIC_BEXTR64:
5212+
return {Type::IntegerType(8, false)};
51995213
case INTRINSIC_F2XM1:
52005214
case INTRINSIC_FBLD:
52015215
case INTRINSIC_FPATAN:

‎arch/x86/il.cpp‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev
982982
0)));
983983
break;
984984

985+
case XED_ICLASS_BEXTR:
986+
{
987+
// Keep extraction atomic and expose the packed control as named start/length inputs.
988+
// A temporary result also preserves inputs when the destination aliases the control.
989+
il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(LLIL_TEMP(0))},
990+
opOneLen == 8 ? INTRINSIC_BEXTR64 : INTRINSIC_BEXTR32,
991+
{ReadILOperand(il, xedd, addr, 1, 1),
992+
il.LowPart(1, ReadILOperand(il, xedd, addr, 2, 2)),
993+
il.LowPart(1, il.LogicalShiftRight(opTreLen, ReadILOperand(il, xedd, addr, 2, 2), il.Const(1, 8)))},
994+
noFlags ? 0 : IL_FLAGWRITE_BEXTR));
995+
// Only ZF depends on the result. Keep unspecified flags on the intrinsic so that
996+
// semantic flag resolution cannot infer SF from the destination's sign bit.
997+
il.AddInstruction(il.Operand(0, il.SetRegister(opOneLen, xed_decoded_inst_get_reg(xedd, opOne_name),
998+
il.Register(opOneLen, LLIL_TEMP(0)), noFlags ? 0 : IL_FLAGWRITE_Z)));
999+
break;
1000+
}
1001+
9851002
case XED_ICLASS_BT:
9861003
il.AddInstruction(il.SetFlag(IL_FLAG_C,
9871004
il.TestBit(opOneLen,

‎arch/x86/il.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ struct DISASSEMBLY_OPTIONS
5757
#define IL_FLAGWRITE_SHRD1 13
5858
#define IL_FLAGWRITE_CUO 14
5959
#define IL_FLAGWRITE_PTEST 15
60+
#define IL_FLAGWRITE_BEXTR 16
61+
#define IL_FLAGWRITE_Z 17
6062

6163
#define IL_FLAG_CLASS_INT 0 // Default
6264
#define IL_FLAG_CLASS_X87COM 1
@@ -114,6 +116,8 @@ enum X86_INTRINSIC
114116
INTRINSIC_FXTRACT,
115117
INTRINSIC_FYL2X,
116118
INTRINSIC_FYL2XP1,
119+
INTRINSIC_BEXTR32,
120+
INTRINSIC_BEXTR64,
117121
// below are for vector instrinsics
118122
// copied from public/arch/x86/xedInc/xed-iform-enum.h
119123
INTRINSIC_XED_IFORM_INVALID = 1000,

0 commit comments

Comments
 (0)