diff options
| -rw-r--r-- | miasm/arch/x86/sem.py | 91 | ||||
| -rw-r--r-- | miasm/ir/translators/C.py | 43 |
2 files changed, 73 insertions, 61 deletions
diff --git a/miasm/arch/x86/sem.py b/miasm/arch/x86/sem.py index 52858ad2..b924c44f 100644 --- a/miasm/arch/x86/sem.py +++ b/miasm/arch/x86/sem.py @@ -4781,66 +4781,71 @@ def palignr(ir, instr, dst, src, imm): return [m2_expr.ExprAssign(dst, result)], [] -def _signed_saturation(expr, dst_size): +def _signed_to_signed_saturation(expr, dst_size): """Saturate the expr @expr for @dst_size bit Signed saturation return MAX_INT / MIN_INT or value depending on the value """ assert expr.size > dst_size median = 1 << (dst_size - 1) + min_int = m2_expr.ExprInt(- median, dst_size) max_int = m2_expr.ExprInt(median - 1, dst_size) - signed = expr.msb() - value_unsigned = (expr ^ expr.mask) + m2_expr.ExprInt(1, expr.size) - # Re-use the sign bit - value = m2_expr.ExprCompose(expr[:dst_size - 1], signed) - - # Bit hack: to avoid a double signed comparison, use mask - # ie., in unsigned, 0xXY > 0x0f iff X is not null - - # if expr >s 0 - # if expr[dst_size - 1:] > 0: # bigger than max_int - # -> max_int - # else - # -> value - # else # negative - # if expr[dst_size:-1] > 0: # smaller than min_int - # -> value - # else - # -> min_int + + test_min_int = min_int.signExtend(expr.size) + test_max_int = max_int.signExtend(expr.size) + + value = expr[:dst_size] return m2_expr.ExprCond( - signed, - m2_expr.ExprCond(value_unsigned[dst_size - 1:], - min_int, - value), - m2_expr.ExprCond(expr[dst_size - 1:], - max_int, - value), + m2_expr.ExprOp( + m2_expr.TOK_INF_EQUAL_SIGNED, + expr, + test_min_int + ), + min_int, + m2_expr.ExprCond( + m2_expr.ExprOp( + m2_expr.TOK_INF_SIGNED, + expr, + test_max_int + ), + value, + max_int + ) ) -def _unsigned_saturation(expr, dst_size): +def _signed_to_unsigned_saturation(expr, dst_size): """Saturate the expr @expr for @dst_size bit Unsigned saturation return MAX_INT or value depending on the value """ assert expr.size > dst_size zero = m2_expr.ExprInt(0, dst_size) - max_int = m2_expr.ExprInt(-1, dst_size) - value = expr[:dst_size] - signed = expr.msb() + test_zero = m2_expr.ExprInt(0, expr.size) + max_int = m2_expr.ExprInt(-1, dst_size) + test_max_int = max_int.zeroExtend(expr.size) - # Bit hack: to avoid a double signed comparison, use mask - # ie., in unsigned, 0xXY > 0x0f iff X is not null + value = expr[:dst_size] return m2_expr.ExprCond( - signed, + m2_expr.ExprOp( + m2_expr.TOK_INF_EQUAL_SIGNED, + expr, + test_zero + ), zero, - m2_expr.ExprCond(expr[dst_size:], - max_int, - value), + m2_expr.ExprCond( + m2_expr.ExprOp( + m2_expr.TOK_INF_SIGNED, + expr, + test_max_int + ), + value, + max_int + ) ) @@ -4849,7 +4854,7 @@ def packsswb(ir, instr, dst, src): out = [] for source in [dst, src]: for start in range(0, dst.size, 16): - out.append(_signed_saturation(source[start:start + 16], 8)) + out.append(_signed_to_signed_saturation(source[start:start + 16], 8)) return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] @@ -4857,7 +4862,7 @@ def packssdw(ir, instr, dst, src): out = [] for source in [dst, src]: for start in range(0, dst.size, 32): - out.append(_signed_saturation(source[start:start + 32], 16)) + out.append(_signed_to_signed_saturation(source[start:start + 32], 16)) return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] @@ -4865,7 +4870,7 @@ def packuswb(ir, instr, dst, src): out = [] for source in [dst, src]: for start in range(0, dst.size, 16): - out.append(_unsigned_saturation(source[start:start + 16], 8)) + out.append(_signed_to_unsigned_saturation(source[start:start + 16], 8)) return [m2_expr.ExprAssign(dst, m2_expr.ExprCompose(*out))], [] @@ -4876,7 +4881,7 @@ def _saturation_sub_unsigned(expr): # 0x48 - 0xd7 in 8 bit, should saturate arg1 = expr.args[0].zeroExtend(expr.size + 1) arg2 = expr.args[1].args[0].zeroExtend(expr.size + 1) - return _unsigned_saturation(arg1 - arg2, expr.size) + return _signed_to_unsigned_saturation(arg1 - arg2, expr.size) def _saturation_sub_signed(expr): assert expr.is_op("+") and len(expr.args) == 2 and expr.args[-1].is_op("-") @@ -4884,7 +4889,7 @@ def _saturation_sub_signed(expr): # Compute the subtraction on two more bits, see _saturation_sub_unsigned arg1 = expr.args[0].signExtend(expr.size + 2) arg2 = expr.args[1].args[0].signExtend(expr.size + 2) - return _signed_saturation(arg1 - arg2, expr.size) + return _signed_to_signed_saturation(arg1 - arg2, expr.size) def _saturation_add(expr): assert expr.is_op("+") and len(expr.args) == 2 @@ -4895,7 +4900,7 @@ def _saturation_add(expr): arg1 = expr.args[0].zeroExtend(expr.size + 1) arg2 = expr.args[1].zeroExtend(expr.size + 1) - # We can also use _unsigned_saturation with two additional bits (to + # We can also use _signed_to_unsigned_saturation with two additional bits (to # distinguish minus and overflow case) # The resulting expression being more complicated with an impossible case # (signed=True), we rewrite the rule here @@ -4911,7 +4916,7 @@ def _saturation_add_signed(expr): arg1 = expr.args[0].signExtend(expr.size + 2) arg2 = expr.args[1].signExtend(expr.size + 2) - return _signed_saturation(arg1 + arg2, expr.size) + return _signed_to_signed_saturation(arg1 + arg2, expr.size) # Saturate SSE operations diff --git a/miasm/ir/translators/C.py b/miasm/ir/translators/C.py index 9a96487a..6be5d961 100644 --- a/miasm/ir/translators/C.py +++ b/miasm/ir/translators/C.py @@ -36,6 +36,16 @@ TOK_CMP_TO_BIGNUM_C = { } +def get_c_common_next_pow2(size): + # For uncommon expression size, use at least uint8 + size = max(size, 8) + next_power = 1 + while next_power < size: + next_power <<= 1 + size = next_power + return size + + class TranslatorC(Translator): "Translate a Miasm expression to an equivalent C code" @@ -419,21 +429,28 @@ class TranslatorC(Translator): TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED, ]: - arg0 = self.from_expr(expr.args[0]) - arg1 = self.from_expr(expr.args[1]) - + arg0, arg1 = expr.args if expr.size <= self.NATIVE_INT_MAX_SIZE: + size = get_c_common_next_pow2(arg0.size) op = TOK_CMP_TO_NATIVE_C[expr.op] if expr.op in [TOK_INF_SIGNED, TOK_INF_EQUAL_SIGNED]: - cast = "(int%d_t)" % expr.args[0].size + arg0 = arg0.signExtend(size) + arg1 = arg1.signExtend(size) + arg0_C = self.from_expr(arg0) + arg1_C = self.from_expr(arg1) + cast = "(int%d_t)" % size else: - cast = "(uint%d_t)" % expr.args[0].size + arg0 = arg0.signExtend(size) + arg1 = arg1.signExtend(size) + arg0_C = self.from_expr(arg0) + arg1_C = self.from_expr(arg1) + cast = "(uint%d_t)" % size out = '((%s%s %s %s%s)?1:0)' % ( cast, - arg0, + arg0_C, op, cast, - arg1 + arg1_C ) else: op = TOK_CMP_TO_BIGNUM_C[expr.op] @@ -484,17 +501,7 @@ class TranslatorC(Translator): if expr.size <= self.NATIVE_INT_MAX_SIZE: out = [] - # XXX check mask for 64 bit & 32 bit compat - if expr.size in [8, 16, 32, 64, 128]: - size = expr.size - else: - # Uncommon expression size, use at least uint8 - size = max(expr.size, 8) - next_power = 1 - while next_power <= size: - next_power <<= 1 - size = next_power - + size = get_c_common_next_pow2(expr.size) dst_cast = "uint%d_t" % size for index, arg in expr.iter_args(): out.append("(((%s)(%s & %s)) << %d)" % ( |