Skip to content

Commit

Permalink
Add several common bit operations to RzIL.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rot127 committed Nov 14, 2023
1 parent 221f4da commit f276c71
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 9 deletions.
9 changes: 0 additions & 9 deletions librz/analysis/arch/ppc/ppc_il.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,6 @@
*/
#define DCACHE_LINE_SIZE 128

/**
* \brief Writes to the info log that an unimplemented instruction was encountered and returns an EMPTY() effect.
*/
#define NOT_IMPLEMENTED \
do { \
RZ_LOG_INFO("IL instruction not implemented."); \
return NULL; \
} while (0)

/**
* \brief Unsigned value \p i which is PPC_ARCH_BITS (32 or 64) wide.
*/
Expand Down
213 changes: 213 additions & 0 deletions librz/il/il_routines.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// SPDX-FileCopyrightText: 2023 Rot127 <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

/**
* \file Implements common bit operation perfomed on values.
*/

#include <rz_util/rz_assert.h>
#include <rz_il/rz_il_opcodes.h>
#include <rz_types.h>

/**
* \brief Extracts \p length bits from \p start of \p value and returns them as U32.
*
* Performed operation: ((value >> start) & (-0x1 >> 0x20 - length));
*
* \param value The value to extract the bits from. It must be a bitvector of size 32.
* \param start The start index of the bits to extract. Passed bitvector can be of any width.
* \param length Number of bits to extract. Passed bitvector must be 32bits in size.
*
* \return A 32bit wide bitvector with the extracted value.
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_extract32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length) {
rz_return_val_if_fail(value && start && length, NULL);
RzILOpPure *op_RSHIFT_0 = rz_il_op_new_shiftr(rz_il_op_new_b0(), value, start);
RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x20), length);
RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(32, -1), op_SUB_4);
RzILOpPure *op_AND_6 = rz_il_op_new_log_and(op_RSHIFT_0, op_RSHIFT_5);
return op_AND_6;
}

/**
* \brief Extracts \p length bits from \p start of \p value and returns them as U64.
*
* Performed operation: ((value >> start) & (-0x1 >> 0x40 - length));
*
* \param value The value to extract the bits from. It must be a bitvector of size 64.
* \param start The start index of the bits to extract. Passed bitvector can be of any width.
* \param length Number of bits to extract. Passed bitvector must be 32bits in size.
*
* \return A 64bit wide bitvector with the extracted value.
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_extract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length) {
rz_return_val_if_fail(value && start && length, NULL);
RzILOpPure *op_RSHIFT_0 = rz_il_op_new_shiftr(rz_il_op_new_b0(), value, start);
RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), length);
RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(64, -1), op_SUB_4);
RzILOpPure *op_AND_6 = rz_il_op_new_log_and(op_RSHIFT_0, op_RSHIFT_5);
return op_AND_6;
}

/**
* \brief Extracts \p length bits from \p start from \p value and returns them as S64. The extracted value is sign extended.
*
* Performed operation: (((st64) (value << 0x40 - length - start)) >> 0x40 - length);
*
* \param value The value to extract the bits from. It must be a bitvector of size 64.
* \param start The start index of the bits to extract. Passed bitvector can be of any width.
* \param length Number of bits to extract. Passed bitvector must be 32bits in size.
*
* \return A 64bit wide sign extended bitvector with the extracted value.
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_sextract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length) {
rz_return_val_if_fail(value && start && length, NULL);
RzILOpPure *op_SUB_1 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), length);
RzILOpPure *op_SUB_2 = rz_il_op_new_sub(op_SUB_1, start);
RzILOpPure *op_LSHIFT_3 = rz_il_op_new_shiftl(rz_il_op_new_b0(), value, op_SUB_2);
RzILOpPure *op_SUB_6 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), rz_il_op_pure_dup(length));
RzILOpPure *op_RSHIFT_7 = rz_il_op_new_shiftr_arith(rz_il_op_new_cast(64, rz_il_op_new_b0(), op_LSHIFT_3), op_SUB_6);
return op_RSHIFT_7;
}

/**
* \brief Deposits \p fieldval in \p value. The \p fieldval is inserted at \p start until \p start + \p length (wrapped around).
*
* Performed operation: ((value & (~((-0x1 >> 0x40 - length) << start))) | ((fieldval << start) & ((-0x1 >> 0x40 - length) << start)));
*
* \param value The value to deposit \p fieldval into. It must be a bitvector of size 64.
* \param start The start index to deposit \p fieldval into. Passed bitvector can be of any width.
* \param length Number of bits to deposit. Passed bitvector must be 32bits in size.
* \param fieldval The bits to deposit into \p value into. It must be a bitvector of size 64.
*
* \return \p value where bits[start:length] are replaced with \p fieldval (wrapped around).
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval) {
rz_return_val_if_fail(value && start && length && fieldval, NULL);
RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), length);
RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(64, -1), op_SUB_4);
RzILOpPure *op_LSHIFT_6 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_RSHIFT_5, start);
RzILOpPure *op_NOT_8 = rz_il_op_new_log_not(op_LSHIFT_6);
RzILOpPure *op_AND_9 = rz_il_op_new_log_and(value, op_NOT_8);
RzILOpPure *op_LSHIFT_10 = rz_il_op_new_shiftl(rz_il_op_new_b0(), fieldval, rz_il_op_pure_dup(start));
RzILOpPure *op_AND_11 = rz_il_op_new_log_and(op_LSHIFT_10, rz_il_op_pure_dup(op_LSHIFT_6));
RzILOpPure *op_OR_12 = rz_il_op_new_log_or(op_AND_9, op_AND_11);
return op_OR_12;
}

/**
* \brief Deposits \p fieldval in \p value. The \p fieldval is inserted at \p start until \p start + \p length (wrapped around).
*
* Performed operation: ((value & (~((-0x1 >> 0x20 - length) << start))) | ((fieldval << start) & ((-0x1 >> 0x20 - length) << start)));
*
* \param value The value to deposit \p fieldval into. It must be a bitvector of size 32.
* \param start The start index to deposit \p fieldval into. Passed bitvector can be of any width.
* \param length Number of bits to deposit. Passed bitvector must be 32bits in size.
* \param fieldval The bits to deposit into \p value into. It must be a bitvector of size 32.
*
* \return \p value where bits[start:length] are replaced with \p fieldval (wrapped around).
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval) {
rz_return_val_if_fail(value && start && length && fieldval, NULL);
RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x20), length);
RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(32, -1), op_SUB_4);
RzILOpPure *op_LSHIFT_6 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_RSHIFT_5, start);
RzILOpPure *op_NOT_8 = rz_il_op_new_log_not(op_LSHIFT_6);
RzILOpPure *op_AND_9 = rz_il_op_new_log_and(value, op_NOT_8);
RzILOpPure *op_LSHIFT_10 = rz_il_op_new_shiftl(rz_il_op_new_b0(), fieldval, rz_il_op_pure_dup(start));
RzILOpPure *op_AND_11 = rz_il_op_new_log_and(op_LSHIFT_10, rz_il_op_pure_dup(op_LSHIFT_6));
RzILOpPure *op_OR_12 = rz_il_op_new_log_or(op_AND_9, op_AND_11);
return op_OR_12;
}

/**
* \brief Performes a byte swap of \p t.
*
* Perfomed operation: (((((st32) t) & 0xff00) >> 0x8) | ((((st32) t) & 0xff) << 0x8));
*
* \param t A 16bit wide bitvector for which to swap the bytes.
*
* \return The bitvector \p t with swapped bytes.
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap16(RZ_BORROW RzILOpBitVector *t) {
rz_return_val_if_fail(t, NULL);
RzILOpPure *op_AND_2 = rz_il_op_new_log_and(rz_il_op_new_cast(32, rz_il_op_new_b0(), t), rz_il_op_new_bitv_from_st64(32, 0xff00));
RzILOpPure *op_RSHIFT_4 = rz_il_op_new_shiftr_arith(op_AND_2, rz_il_op_new_bitv_from_st64(32, 8));
RzILOpPure *op_AND_7 = rz_il_op_new_log_and(rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_pure_dup(t)), rz_il_op_new_bitv_from_st64(32, 0xff));
RzILOpPure *op_LSHIFT_9 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_7, rz_il_op_new_bitv_from_st64(32, 8));
RzILOpPure *op_OR_10 = rz_il_op_new_log_or(op_RSHIFT_4, op_LSHIFT_9);
return rz_il_op_new_cast(16, rz_il_op_new_b0(), op_OR_10);
}

/**
* \brief Performes a byte swap of \p t.
*
* Perfomed operation:
* ((t & ((ut32) 0xff)) << 0x18)
* | ((t & ((ut32) 0xff00)) << 0x8))
* | ((t & ((ut32) 0xff0000)) >> 0x8))
* | ((t & ((ut32) 0xff000000)) >> 0x18));
*
* \param t A 32bit wide bitvector for which to swap the bytes.
*
* \return The bitvector \p t with swapped bytes.
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap32(RZ_BORROW RzILOpBitVector *t) {
rz_return_val_if_fail(t, NULL);
RzILOpPure *op_AND_2 = rz_il_op_new_log_and(t, rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff)));
RzILOpPure *op_LSHIFT_4 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_2, rz_il_op_new_bitv_from_st64(32, 24));
RzILOpPure *op_AND_7 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff00)));
RzILOpPure *op_LSHIFT_9 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_7, rz_il_op_new_bitv_from_st64(32, 8));
RzILOpPure *op_OR_10 = rz_il_op_new_log_or(op_LSHIFT_4, op_LSHIFT_9);
RzILOpPure *op_AND_13 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff0000)));
RzILOpPure *op_RSHIFT_15 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_13, rz_il_op_new_bitv_from_st64(32, 8));
RzILOpPure *op_OR_16 = rz_il_op_new_log_or(op_OR_10, op_RSHIFT_15);
RzILOpPure *op_AND_19 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff000000)));
RzILOpPure *op_RSHIFT_21 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_19, rz_il_op_new_bitv_from_st64(32, 24));
RzILOpPure *op_OR_22 = rz_il_op_new_log_or(op_OR_16, op_RSHIFT_21);
return op_OR_22;
}

/**
* \brief Performes a byte swap of \p t.
*
* Perfomed operation:
* ((t & 0xff) << 0x38)
* | ((t & 0xff00) << 0x28))
* | ((t & 0xff0000) << 0x18))
* | ((t & 0xff000000) << 0x8))
* | ((t & 0xff00000000) >> 0x8))
* | ((t & 0xff0000000000) >> 0x18))
* | ((t & 0xff000000000000) >> 0x28))
* | ((t & 0xff00000000000000) >> 0x38));
*
* \param t A 64bit wide bitvector for which to swap the bytes.
*
* \return The bitvector \p t with swapped bytes.
*/
RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap64(RZ_BORROW RzILOpBitVector *t) {
RzILOpPure *op_AND_1 = rz_il_op_new_log_and(t, rz_il_op_new_bitv_from_ut64(64, 0xff));
RzILOpPure *op_LSHIFT_3 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_1, rz_il_op_new_bitv_from_st64(32, 0x38));
RzILOpPure *op_AND_5 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff00));
RzILOpPure *op_LSHIFT_7 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_5, rz_il_op_new_bitv_from_st64(32, 0x28));
RzILOpPure *op_OR_8 = rz_il_op_new_log_or(op_LSHIFT_3, op_LSHIFT_7);
RzILOpPure *op_AND_10 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff0000));
RzILOpPure *op_LSHIFT_12 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_10, rz_il_op_new_bitv_from_st64(32, 24));
RzILOpPure *op_OR_13 = rz_il_op_new_log_or(op_OR_8, op_LSHIFT_12);
RzILOpPure *op_AND_15 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff000000));
RzILOpPure *op_LSHIFT_17 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_15, rz_il_op_new_bitv_from_st64(32, 8));
RzILOpPure *op_OR_18 = rz_il_op_new_log_or(op_OR_13, op_LSHIFT_17);
RzILOpPure *op_AND_20 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff00000000));
RzILOpPure *op_RSHIFT_22 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_20, rz_il_op_new_bitv_from_st64(32, 8));
RzILOpPure *op_OR_23 = rz_il_op_new_log_or(op_OR_18, op_RSHIFT_22);
RzILOpPure *op_AND_25 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff0000000000));
RzILOpPure *op_RSHIFT_27 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_25, rz_il_op_new_bitv_from_st64(32, 24));
RzILOpPure *op_OR_28 = rz_il_op_new_log_or(op_OR_23, op_RSHIFT_27);
RzILOpPure *op_AND_30 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff000000000000));
RzILOpPure *op_RSHIFT_32 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_30, rz_il_op_new_bitv_from_st64(32, 0x28));
RzILOpPure *op_OR_33 = rz_il_op_new_log_or(op_OR_28, op_RSHIFT_32);
RzILOpPure *op_AND_35 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff00000000000000));
RzILOpPure *op_RSHIFT_37 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_35, rz_il_op_new_bitv_from_st64(32, 0x38));
RzILOpPure *op_OR_38 = rz_il_op_new_log_or(op_OR_33, op_RSHIFT_37);
return op_OR_38;
}
1 change: 1 addition & 0 deletions librz/il/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rz_il_sources = [
'il_export_json.c',
'il_graph.c',
'il_opcodes.c',
'il_routines.c',
'il_reg.c',
'il_validate.c',
'il_vm.c',
Expand Down
15 changes: 15 additions & 0 deletions librz/include/rz_il/rz_il_opbuilder_begin.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,19 @@
#define JMP(tgt) rz_il_op_new_jmp(tgt)
#define GOTO(lbl) rz_il_op_new_goto(lbl)

#define NOT_IMPLEMENTED \
do { \
RZ_LOG_INFO("IL instruction not implemented."); \
return NULL; \
} while (0)

#define EXTRACT32(value, start, length) rz_il_extract32(value, start, length)
#define EXTRACT64(value, start, length) rz_il_extract64(value, start, length)
#define SEXTRACT64(value, start, length) rz_il_sextract64(value, start, length)
#define DEPOSIT32(value, start, length, fieldval) rz_il_deposit32(value, start, length, fieldval)
#define DEPOSIT64(value, start, length, fieldval) rz_il_deposit64(value, start, length, fieldval)
#define BSWAP16(t) rz_il_bswap16(t)
#define BSWAP32(t) rz_il_bswap32(t)
#define BSWAP64(t) rz_il_bswap64(t)

#endif
11 changes: 11 additions & 0 deletions librz/include/rz_il/rz_il_opbuilder_end.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,15 @@
#undef JMP
#undef GOTO

#undef NOT_IMPLEMENTED

#undef EXTRACT32
#undef EXTRACT64
#undef SEXTRACT64
#undef DEPOSIT32
#undef DEPOSIT64
#undef BSWAP16
#undef BSWAP32
#undef BSWAP64

#undef RZ_IL_OPBUILDER_BEGIN_H
9 changes: 9 additions & 0 deletions librz/include/rz_il/rz_il_opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,15 @@ RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_frootn(RzFloatRMode rmode, RZ_NONNULL Rz
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fpown(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpBitVector *n);
RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fcompound(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpBitVector *n);

RZ_API RZ_OWN RzILOpBitVector *rz_il_extract32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length);
RZ_API RZ_OWN RzILOpBitVector *rz_il_extract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length);
RZ_API RZ_OWN RzILOpBitVector *rz_il_sextract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length);
RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval);
RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval);
RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap16(RZ_BORROW RzILOpBitVector *t);
RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap32(RZ_BORROW RzILOpBitVector *t);
RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap64(RZ_BORROW RzILOpBitVector *t);

///////////////////////////////
// Opcodes of type 'a effect //

Expand Down

0 comments on commit f276c71

Please sign in to comment.