Skip to content

Commit

Permalink
Add RzIL for floating-point x86 instructions (#3865)
Browse files Browse the repository at this point in the history
* Create `il_fp_ops.inc`, for floating-point instructions' IL ops

* Add IL implementation for `FABS`

 * Also add `x86_il_{get,set}_st_reg` helper functions

* Add IL implementation for `FNINIT` and `FLDCW`

* Add IL implementations for `FNSTCW` and `FNSTSW`

* Add IL implementation for `FNCLEX`

* Add ST push and pop functions

* Fix clang formatting

* Add fucntions for updating FPSW TOP pointer

* Add `FLD` instruction lifitng, FPSW flag support, FP operand support

* Remove `x86_bool_to_bv` and use the standard `BOOL_TO_BV`

* Add implementation for `FST{P}`, and rounding mode support

* Add `FLD` variants for constants

* Fix formatting and build

* Add IL lifting for `FXCH`

* Add width checks to avoid redundant rounding

* Implement IL lifting for `FILD`, `FIST{P}`

    * Add helper functions to inter-convert floating point values and
      integers using the rounding mode in the control word

* FPU stack regs are 80-bit, not 64-bit

* Add RzIL lifting for `FBLD`

* Add RzIL implementation for `FBSTP`

    * An invalid-arithmetic-operand (#IA) exception may occurr if the
      value being converted to the BCD integer cannot fit in an 18-bit
      BCD integer. For the IL's purpose, we just jump to the "int" label
      (stands for interrupt) using `GOTO`.

* Remove all the `EMPTY()` ops after `GOTO()` ops

    * On second thought, using `EMPTY()` ops after `GOTO()` ops is not
      the best idea to indicate end of analysis. Maybe the hooks can
      signal that analysis needs to be restarted.
    * Also, clean up the comments of a bunch of unimplemented ops

* Moved some code around

* Rename "rmode" local variable to "_rmode"

* Add some TODOs for deffered work

* Fix failing asm tests

    * Caused due to the removal of the [empty] opcode

* Implement IL lifting for `FADD` (and some other minor refactoring)

    * Implement the IL lifting for `FADD`: This is not entirely correct
      as of now, because we don't handle setting C1 based on rounding
      up/down, but I think it should be fine for now. Need to tackle
      setting the control word bits later
    * Start using `RzFloatFormat` to describe the float's width instead
      of using an unsigned integer. Provide and expose conversion
      functions between the two

* Use a global to denote when RMode needs to be init, implement FIADD

    * Other minor refactor which fixes the CI (hopefully)

* Implement `FMUL` and `FIMUL`

    * Extract the common code into a C macro

* Implement RzIL for `FSUB` and `FISUB`

    * Also add `x86_il_fsub_with_rmode` helper

* Implement RzIL for `FSUBR` and `FISUBR`

    * Reuse the implementation of `x86_il_fsub_with_rmode` and just pass
      the arguments in the opposite order

* Add RzIL implementation for `FDIV`, `FIDIV`, `FDIVR`, `FIDIVR`

* Add pop versions of floating point arithmetic instuctions

    * Add a new macro `X86_ARITHMETIC_POP_IL` macro for the same
    * Fix a typo
    * Add a note for using `X86_INS_PFADD` for FADDP instruction on
      Capstone version newer than 4

* Add RzIL implementations for `FCOM`, `FCOMP` and `FCOMPP`

* Add RzIL lifting for `FUCOM` and `FCOMI` families of instructions

* Implement RzIL lifting for `FCHS` and `FTST`

* Add RzIL implementation for `FRNDINT` and `FSQRT`

* Add RzIL implementation for `FNOP` and `FISTTP`

* Remove global variable `use_rmode` and use pass around a context instead

    * Define a new `X86ILContext` struct to pass around information
      whether we need to intitialize the rouding mode or not
    * Remove the global variable which was previously responsible for
      doing so

* Add RzIL for `FICOM` and `FICOMP`, add register bindings and fix bugs

* Make `rz-test` more robust against IL outputs with newlines in them

* Add RzIL tests in db/asm for x86 FPU instructions

* Fix the bug when using `FADDP` with Capstone version > 4

* Fix remaining db tests

* Remove tests for `FSTSW` or `FSTCW` instructions

    * We already test `WAIT` (in `db/asm/x86_32`) and `FSTSW` (or
      `FSTCW`) (in `db/asm/x86_64`)
    * Remove the newline replacement code in `rz-test` as well, since we
      wouldn't need that functionality anymore

* Add asm tests for math constant push instructions

* Add `RZ_IPI` annotation for all the functions exposed through the header

* Add `RZ_OWN`, `RZ_BORROW` and `RZ_NONNULL` annotations

* Add Doxygen doc for `ctx` argument

* Add description for the `EXEC_WITH_RMODE` macro

* Move the non-null check for `ctx` inside the valid branch

    * When we pop the FPU stack we pass in a `NULL` context since no
      resizing would be needed, which causes a failure if the non-null
      check for the `ctx` is outside the branch
    * Fixes failing tests in `db/asm`

* Minor bug fixes + make the annotations less strict than they need to be

* Minor bug fixes

    * Incorrect implementation for `RET` and `CALL`
    * Swapped arguments for shift right

* Fix asm tests for `JMP` and `RET` instructions

* Fix indexing error for `FXCH`

* Review changes

    * Move all unimplemented instructions to the end
    * Remove support for Capstone version less than 4
  • Loading branch information
DMaroo authored Feb 18, 2024
1 parent 5c79c42 commit de4a129
Show file tree
Hide file tree
Showing 11 changed files with 1,641 additions and 278 deletions.
573 changes: 533 additions & 40 deletions librz/analysis/arch/x86/common.c

Large diffs are not rendered by default.

120 changes: 105 additions & 15 deletions librz/analysis/arch/x86/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#define X86_BIT(x) UN(1, x)
#define X86_TO32(x) UNSIGNED(32, x)

#define IL_LIFTER(mnem) static RzILOpEffect *x86_il_##mnem(const X86ILIns *ins, ut64 pc, RzAnalysis *analysis)
#define IL_LIFTER(mnem) static RzILOpEffect *x86_il_##mnem(const X86ILIns *ins, ut64 pc, RzAnalysis *analysis, X86ILContext *ctx)

// Namespace clash with android-ndk-25b's x86_64-linux-android/asm/processor-flags.h
#undef X86_EFLAGS_CF
Expand Down Expand Up @@ -84,24 +84,114 @@ typedef enum x86_eflags_t {

extern const char *x86_eflags_registers[X86_EFLAGS_ENDING];

RzILOpPure *x86_il_get_reg_bits(X86Reg reg, int bits, uint64_t pc);
RzILOpEffect *x86_il_set_reg_bits(X86Reg reg, RzILOpPure *val, int bits);
RZ_IPI RzILOpPure *x86_il_get_reg_bits(X86Reg reg, int bits, uint64_t pc);
RZ_IPI RzILOpEffect *x86_il_set_reg_bits(X86Reg reg, RZ_OWN RZ_NONNULL RzILOpPure *val, int bits);

RzILOpPure *x86_il_get_operand_bits(X86Op op, int analysis_bits, ut64 pc, int implicit_size);
RzILOpEffect *x86_il_set_operand_bits(X86Op op, RzILOpPure *val, int bits, ut64 pc);
RZ_IPI RzILOpPure *x86_il_get_operand_bits(X86Op op, int analysis_bits, ut64 pc, int implicit_size);
RZ_IPI RzILOpEffect *x86_il_set_operand_bits(X86Op op, RZ_OWN RZ_NONNULL RzILOpPure *val, int bits, ut64 pc);

RzILOpPure *x86_il_get_memaddr_bits(X86Mem mem, int bits, ut64 pc);
RzILOpPure *x86_il_get_memaddr_segment_bits(X86Mem mem, X86Reg segment, int bits, ut64 pc);
RzILOpEffect *x86_il_set_mem_bits(X86Mem mem, RzILOpPure *val, int bits, ut64 pc);
RZ_IPI RzILOpPure *x86_il_get_memaddr_bits(X86Mem mem, int bits, ut64 pc);
RZ_IPI RzILOpPure *x86_il_get_memaddr_segment_bits(X86Mem mem, X86Reg segment, int bits, ut64 pc);
RZ_IPI RzILOpEffect *x86_il_set_mem_bits(X86Mem mem, RZ_OWN RZ_NONNULL RzILOpPure *val, int bits, ut64 pc);

RzILOpBool *x86_il_is_sub_borrow(RZ_OWN RzILOpPure *res, RZ_OWN RzILOpPure *x, RZ_OWN RzILOpPure *y);
RzILOpBitVector *x86_bool_to_bv(RzILOpBool *b, unsigned int bits);
RZ_IPI RzILOpBool *x86_il_is_add_carry(RZ_OWN RZ_NONNULL RzILOpPure *res, RZ_OWN RZ_NONNULL RzILOpPure *x, RZ_OWN RZ_NONNULL RzILOpPure *y);
RZ_IPI RzILOpBool *x86_il_is_sub_borrow(RZ_OWN RZ_NONNULL RzILOpPure *res, RZ_OWN RZ_NONNULL RzILOpPure *x, RZ_OWN RZ_NONNULL RzILOpPure *y);
RZ_IPI RzILOpBool *x86_il_is_add_overflow(RZ_OWN RZ_NONNULL RzILOpPure *res, RZ_OWN RZ_NONNULL RzILOpPure *x, RZ_OWN RZ_NONNULL RzILOpPure *y);
RZ_IPI RzILOpBool *x86_il_is_sub_underflow(RZ_OWN RZ_NONNULL RzILOpPure *res, RZ_OWN RZ_NONNULL RzILOpPure *x, RZ_OWN RZ_NONNULL RzILOpPure *y);

RzILOpEffect *x86_il_set_result_flags_bits(RZ_OWN RzILOpPure *result, int bits);
RzILOpEffect *x86_il_set_arithmetic_flags_bits(RZ_OWN RzILOpPure *res, RZ_OWN RzILOpPure *x, RZ_OWN RzILOpPure *y, bool addition, int bits);
RzILOpEffect *x86_il_set_arithmetic_flags_except_cf_bits(RZ_OWN RzILOpPure *res, RZ_OWN RzILOpPure *x, RZ_OWN RzILOpPure *y, bool addition, int bits);
RZ_IPI RzILOpEffect *x86_il_set_result_flags_bits(RZ_OWN RZ_NONNULL RzILOpPure *result, int bits);
RZ_IPI RzILOpEffect *x86_il_set_arithmetic_flags_bits(RZ_OWN RZ_NONNULL RzILOpPure *res, RZ_OWN RZ_NONNULL RzILOpPure *x, RZ_OWN RZ_NONNULL RzILOpPure *y, bool addition, int bits);
RZ_IPI RzILOpEffect *x86_il_set_arithmetic_flags_except_cf_bits(RZ_OWN RZ_NONNULL RzILOpPure *res, RZ_OWN RZ_NONNULL RzILOpPure *x, RZ_OWN RZ_NONNULL RzILOpPure *y, bool addition, int bits);

RzILOpPure *x86_il_get_flags(unsigned int size);
RzILOpEffect *x86_il_set_flags(RZ_OWN RzILOpPure *val, unsigned int size);
RZ_IPI RzILOpPure *x86_il_get_flags(unsigned int size);
RZ_IPI RzILOpEffect *x86_il_set_flags(RZ_OWN RZ_NONNULL RzILOpPure *val, unsigned int size);

/* Capstone does not have the following FPU registers. */

/* FPU control word */
#define X86_REG_FPU_CW "cwd"
/* FPU tag word */
#define X86_REG_FPU_TW "ftw"
/* FPU last instruction opcode */
#define X86_REG_FPU_OP "fop"
/* FPU instruction pointer */
#define X86_REG_FPU_IP "frip"
/* FPU data pointer */
#define X86_REG_FPU_DP "frdp"

typedef enum {
X86_FPU_C0 = 8,
X86_FPU_C1 = 9,
X86_FPU_C2 = 10,
X86_FPU_C3 = 14,
} X86FPUFlags;

RZ_IPI bool x86_il_is_st_reg(X86Reg reg);

/* Need to pass in val_size as a param to avoid unnecessary rounding of val. */

RZ_IPI RzILOpFloat *x86_il_get_st_reg(X86Reg reg);
RZ_IPI RzILOpEffect *x86_il_set_st_reg_ctx(X86Reg reg, RZ_OWN RZ_NONNULL RzILOpFloat *val, RzFloatFormat val_format, RZ_BORROW X86ILContext *ctx);

#define x86_il_set_st_reg(reg, val, val_format) x86_il_set_st_reg_ctx(reg, val, val_format, ctx)

RZ_IPI RzILOpEffect *x86_il_set_fpu_stack_top(RZ_OWN RZ_NONNULL RzILOpPure *top);
RZ_IPI RzILOpPure *x86_il_get_fpu_stack_top();

RZ_IPI RzILOpEffect *x86_il_st_push_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *val, RzFloatFormat val_format, RZ_BORROW X86ILContext *ctx);
RZ_IPI RzILOpEffect *x86_il_st_pop();

#define x86_il_st_push(val, val_format) x86_il_st_push_ctx(val, val_format, ctx)

#define X86_IL_ST_POP(val, eff) \
do { \
val = x86_il_get_st_reg(X86_REG_ST0); \
eff = x86_il_st_pop(); \
} while (0)

RZ_IPI RzILOpPure *x86_il_get_fpu_flag(X86FPUFlags flag);
RZ_IPI RzILOpEffect *x86_il_set_fpu_flag(X86FPUFlags flag, RZ_OWN RZ_NONNULL RzILOpBool *value);

RZ_IPI RzILOpPure *x86_il_fpu_get_rmode();

RZ_IPI RzILOpEffect *init_rmode();

RZ_IPI RzILOpFloat *x86_il_resize_floating_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *val, RzFloatFormat format, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_floating_from_int_ctx(RZ_OWN RZ_NONNULL RzILOpBitVector *int_val, RzFloatFormat format, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpBitVector *x86_il_int_from_floating_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *float_val, ut32 width, RZ_BORROW RZ_NONNULL X86ILContext *ctx);

RZ_IPI RzILOpFloat *x86_il_fadd_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_OWN RZ_NONNULL RzILOpFloat *y, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_fmul_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_OWN RZ_NONNULL RzILOpFloat *y, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_fsub_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_OWN RZ_NONNULL RzILOpFloat *y, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_fsubr_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_OWN RZ_NONNULL RzILOpFloat *y, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_fdiv_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_OWN RZ_NONNULL RzILOpFloat *y, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_fdivr_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_OWN RZ_NONNULL RzILOpFloat *y, RZ_BORROW RZ_NONNULL X86ILContext *ctx);
RZ_IPI RzILOpFloat *x86_il_fsqrt_with_rmode_ctx(RZ_OWN RZ_NONNULL RzILOpFloat *x, RZ_BORROW RZ_NONNULL X86ILContext *ctx);

#define x86_il_resize_floating(val, format) x86_il_resize_floating_ctx(val, format, ctx)
#define x86_il_floating_from_int(int_val, format) x86_il_floating_from_int_ctx(int_val, format, ctx)
#define x86_il_int_from_floating(float_val, width) x86_il_int_from_floating_ctx(float_val, width, ctx)
#define x86_il_fadd_with_rmode(x, y) x86_il_fadd_with_rmode_ctx(x, y, ctx)
#define x86_il_fmul_with_rmode(x, y) x86_il_fmul_with_rmode_ctx(x, y, ctx)
#define x86_il_fsub_with_rmode(x, y) x86_il_fsub_with_rmode_ctx(x, y, ctx)
#define x86_il_fsubr_with_rmode(x, y) x86_il_fsubr_with_rmode_ctx(x, y, ctx)
#define x86_il_fdiv_with_rmode(x, y) x86_il_fdiv_with_rmode_ctx(x, y, ctx)
#define x86_il_fdivr_with_rmode(x, y) x86_il_fdivr_with_rmode_ctx(x, y, ctx)
#define x86_il_fsqrt_with_rmode(x) x86_il_fsqrt_with_rmode_ctx(x, ctx)

RZ_IPI RzILOpPure *x86_il_get_floating_operand_bits(X86Op op, int analysis_bits, ut64 pc);

#define x86_il_get_floating_op(opnum) \
x86_il_get_floating_operand_bits(ins->structure->operands[opnum], analysis->bits, pc)

RZ_IPI RzFloatFormat x86_width_to_format(ut8 width);
RZ_IPI ut8 x86_format_to_width(RzFloatFormat format);

RZ_IPI RzILOpEffect *x86_il_set_floating_operand_bits_ctx(X86Op op, RZ_OWN RZ_NONNULL RzILOpFloat *val, RzFloatFormat val_format, int bits, ut64 pc, RZ_BORROW X86ILContext *ctx);

#define x86_il_set_floating_op(opnum, val, val_format) \
x86_il_set_floating_operand_bits_ctx(ins->structure->operands[opnum], val, val_format, analysis->bits, pc, ctx)

RZ_IPI RzILOpEffect *x86_il_clear_fpsw_flags();

#endif // X86_IL_COMMON_H
Loading

0 comments on commit de4a129

Please sign in to comment.