-
-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add several common bit operations to RzIL. #3977
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) & (~0U >> (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) & (~0ULL >> (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 must be 32bits in size. | ||
* \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. | ||
* | ||
* Performed operation: ((value & (~((~0ULL >> (0x40 - length)) << start))) | ((fieldval << start) & ((~0ULL >> (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 | ||
*/ | ||
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. | ||
* | ||
* Performed operation: ((value & (~((~0U >> (0x20 - length)) << start))) | ((fieldval << start) & ((~0U >> (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. | ||
*/ | ||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm very ok with this, but i wonder if we should just implement the BitVector version directly instead of adding so much IL. because if we do,
rz_il_bswapXX
can become justrz_il_bswap
, same for the othersThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this would be better. I did it this way because it was low effort with the compiler and don't really have the time currently to implement them for the bitvectors.
Could we open an issue about it? Since the RzIL API for those ones will stay the same anyways