-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
The current set of eflags is incomplete; it doesn't include any of the System/IOPL flags. It also includes access specifiers that aren't particularly valuable for semantic analysis (e.g., X86_EFLAGS_PRIOR*
that indicate reserved bits should be set to their prior value). There are also register/access combinations that aren't used by any instructions that I could find in the latest SDM[1] or in the datafiles from Xed v2024.11.04 (e.g., X86_EFLAGS_SET_IF
).
It's not possible to fix these within the confines of the current implementation because the X86_EFLAGS
macros already use 58 of the available 64 bits, macros can't be removed, and the unused/unusable ones can't be set to a dummy value (this could lead to redundant switch cases in user code). We're left with a need for a new implementation. Here is my proposal based on what Zydis does (code comments omitted for brevity).
// shift step could be 1?
#define CS_CPUFLAG_CF (1UL << 0)
#define CS_CPUFLAG_PF (1UL << 2)
#define CS_CPUFLAG_AF (1UL << 4)
#define CS_CPUFLAG_ZF (1UL << 6)
#define CS_CPUFLAG_SF (1UL << 7)
#define CS_CPUFLAG_TF (1UL << 8)
#define CS_CPUFLAG_IF (1UL << 9)
#define CS_CPUFLAG_DF (1UL << 10)
#define CS_CPUFLAG_OF (1UL << 11)
#define CS_CPUFLAG_IOPL (1UL << 12)
#define CS_CPUFLAG_NT (1UL << 14)
#define CS_CPUFLAG_RF (1UL << 16)
#define CS_CPUFLAG_VM (1UL << 17)
#define CS_CPUFLAG_AC (1UL << 18)
#define CS_CPUFLAG_VIF (1UL << 19)
#define CS_CPUFLAG_VIP (1UL << 20)
#define CS_CPUFLAG_ID (1UL << 21)
#define CS_FPUFLAG_C0 (1UL << 0)
#define CS_FPUFLAG_C1 (1UL << 1)
#define CS_FPUFLAG_C2 (1UL << 2)
#define CS_FPUFLAG_C3 (1UL << 3)
typedef struct cs_cpu_flag_state {
uint32_t tested;
uint32_t modified;
uint32_t set_0;
uint32_t set_1;
uint32_t undefined;
} cs_cpu_flag_state;
typedef struct cs_cpu_flags {
cs_cpu_flag_state eflags;
cs_cpu_flag_state fpu_flags;
} cs_cpu_flags;
typedef struct cs_x86 {
// ...
union {
/// EFLAGS updated by this instruction.
/// This can be formed from OR combination of X86_EFLAGS_* symbols in x86.h
uint64_t eflags;
/// FPU_FLAGS updated by this instruction.
/// This can be formed from OR combination of X86_FPU_FLAGS_* symbols in x86.h
uint64_t fpu_flags;
/// Version 2 of all cpu flags updated by this instruction.
cs_cpu_flags const* flags;
};
// ...
} cs_x86;
As long as sizeof(void*) == sizeof(uint64_t)
, this wouldn't be an ABI break.
The hard part will be determining how to fill out both flag inputs. One possibility would be to simply duplicate the information in X86MappingInsnOp.inc.
// X86Mapping.c
typedef struct insn_op {
uint64_t flags; // how this instruction update EFLAGS(arithmetic instructions) of FPU FLAGS(for FPU instructions)
uint8_t access[6];
cs_cpu_flags flags_v2;
} insn_op;
// X86MappingInsnOp.inc
{ /* X86_COM_FIr, X86_INS_FCOMI: fcomi */
{X86_EFLAGS_MODIFY_CF | X86_EFLAGS_MODIFY_PF | X86_EFLAGS_RESET_AF | X86_EFLAGS_MODIFY_ZF | X86_EFLAGS_RESET_SF | X86_EFLAGS_MODIFY_OF},
{ CS_AC_READ | CS_AC_WRITE, 0 },
{
{// CPU
{}, // tested
{CS_CPUFLAG_CF | CS_CPUFLAG_PF | CS_CPUFLAG_ZF}, // modified
{CS_CPUFLAG_AF | CS_CPUFLAG_SF | CS_CPUFLAG_OF}, // set_0
{}, // set_1
{}, // undefined
},
{// FPU
{}, // tested
{}, // modified
{}, // set_0
{CS_FPUFLAG_C1}, // set_1
{}, // undefined
}
},
},
Of course, nearly all instructions wouldn't need to completely fill out the FPU part. This is a "maximal" example that also solves #2680.
There are lots of details left out like how to manage moving this information into the frontend. But my goal is to start a conversation on how we might be able to do this without needing to wait for a big rewrite like moving to Zydis (ping #2505).
Here is the complete set of flags and specifiers from Xed:
Note: pop
and ah
are really mod
, 0
is reset, and 1
is set.
eflags
----------------------------------
ac = {mod, pop, tst}
af = {0, ah, mod, pop, tst, u}
cf = {0, 1, ah, mod, pop, tst, u}
df = {0, 1, mod, pop, tst}
id = {mod, pop, tst}
if = {0, mod, pop, tst}
iopl = {mod, pop, tst}
nt = {mod, pop, tst}
of = {0, mod, pop, tst, u}
pf = {0, ah, mod, pop, tst, u}
rf = {0, mod, pop, tst}
sf = {0, ah, mod, pop, tst, u}
tf = {0, mod, pop, tst}
vif = {mod, pop, tst}
vip = {mod, pop, tst}
vm = {0, mod, pop, tst}
zf = {ah, mod, pop, tst, u}
fpu flags
----------------------------------
fc0 = {mod, u}
fc1 = {mod, u}
fc2 = {mod, u}
fc3 = {mod, u}


[1] Intel 64 and IA-32 Architectures Software Developer’s Manual
Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4
June 2025