diff options
Diffstat (limited to 'miasm2')
| -rw-r--r-- | miasm2/arch/aarch64/sem.py | 2 | ||||
| -rw-r--r-- | miasm2/arch/arm/sem.py | 2 | ||||
| -rw-r--r-- | miasm2/arch/mips32/sem.py | 4 | ||||
| -rw-r--r-- | miasm2/arch/ppc/sem.py | 2 | ||||
| -rw-r--r-- | miasm2/arch/x86/sem.py | 4 | ||||
| -rw-r--r-- | miasm2/expression/expression_helper.py | 2 | ||||
| -rw-r--r-- | miasm2/expression/simplifications.py | 10 | ||||
| -rw-r--r-- | miasm2/expression/simplifications_common.py | 423 | ||||
| -rw-r--r-- | miasm2/ir/translators/C.py | 2 | ||||
| -rw-r--r-- | miasm2/ir/translators/smt2.py | 4 | ||||
| -rw-r--r-- | miasm2/ir/translators/z3_ir.py | 10 | ||||
| -rw-r--r-- | miasm2/jitter/bn.c | 6 | ||||
| -rw-r--r-- | miasm2/jitter/bn.h | 4 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore.py | 12 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore_python.py | 209 | ||||
| -rw-r--r-- | miasm2/jitter/llvmconvert.py | 8 | ||||
| -rw-r--r-- | miasm2/jitter/op_semantics.c | 18 | ||||
| -rw-r--r-- | miasm2/jitter/op_semantics.h | 24 |
18 files changed, 539 insertions, 207 deletions
diff --git a/miasm2/arch/aarch64/sem.py b/miasm2/arch/aarch64/sem.py index f22f0c07..e4702a4f 100644 --- a/miasm2/arch/aarch64/sem.py +++ b/miasm2/arch/aarch64/sem.py @@ -809,7 +809,7 @@ def udiv(arg1, arg2, arg3): @sbuild.parse def sdiv(arg1, arg2, arg3): if arg3: - arg1 = ExprOp('idiv', arg2, arg3) + arg1 = ExprOp('sdiv', arg2, arg3) else: exception_flags = ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size) diff --git a/miasm2/arch/arm/sem.py b/miasm2/arch/arm/sem.py index b5ab60d0..64403206 100644 --- a/miasm2/arch/arm/sem.py +++ b/miasm2/arch/arm/sem.py @@ -592,7 +592,7 @@ def sdiv(ir, instr, a, b, c=None): - r = ExprOp("idiv", b, c) + r = ExprOp("sdiv", b, c) do_div = [] do_div.append(ExprAssign(a, r)) dst = get_dst(a) diff --git a/miasm2/arch/mips32/sem.py b/miasm2/arch/mips32/sem.py index a57d2200..62a85355 100644 --- a/miasm2/arch/mips32/sem.py +++ b/miasm2/arch/mips32/sem.py @@ -393,8 +393,8 @@ def multu(arg1, arg2): @sbuild.parse def div(arg1, arg2): """Divide (signed) @arg1 by @arg2 and stores the remaining/result in $R_HI/$R_LO""" - R_LO = ExprOp('idiv' ,arg1, arg2) - R_HI = ExprOp('imod', arg1, arg2) + R_LO = ExprOp('sdiv' ,arg1, arg2) + R_HI = ExprOp('smod', arg1, arg2) @sbuild.parse def divu(arg1, arg2): diff --git a/miasm2/arch/ppc/sem.py b/miasm2/arch/ppc/sem.py index 969a8002..44895624 100644 --- a/miasm2/arch/ppc/sem.py +++ b/miasm2/arch/ppc/sem.py @@ -165,7 +165,7 @@ def mn_do_div(ir, instr, rd, ra, rb): if has_u: op = 'udiv' else: - op = 'idiv' + op = 'sdiv' rvalue = ExprOp(op, ra, rb) diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py index 244aff30..e01adcbc 100644 --- a/miasm2/arch/x86/sem.py +++ b/miasm2/arch/x86/sem.py @@ -1754,8 +1754,8 @@ def idiv(ir, instr, src1): else: raise ValueError('div arg not impl', src1) - c_d = m2_expr.ExprOp('idiv', src2, src1.signExtend(src2.size)) - c_r = m2_expr.ExprOp('imod', src2, src1.signExtend(src2.size)) + c_d = m2_expr.ExprOp('sdiv', src2, src1.signExtend(src2.size)) + c_r = m2_expr.ExprOp('smod', src2, src1.signExtend(src2.size)) # if 8 bit div, only ax is affected if size == 8: diff --git a/miasm2/expression/expression_helper.py b/miasm2/expression/expression_helper.py index c503ebfc..8065df9b 100644 --- a/miasm2/expression/expression_helper.py +++ b/miasm2/expression/expression_helper.py @@ -80,7 +80,7 @@ def merge_sliceto_slice(expr): op_propag_cst = ['+', '*', '^', '&', '|', '>>', '<<', "a>>", ">>>", "<<<", - "/", "%", 'idiv', 'imod', 'umod', 'udiv','**'] + "/", "%", 'sdiv', 'smod', 'umod', 'udiv','**'] def is_pure_int(e): diff --git a/miasm2/expression/simplifications.py b/miasm2/expression/simplifications.py index 3f50fc1a..8ea9c41f 100644 --- a/miasm2/expression/simplifications.py +++ b/miasm2/expression/simplifications.py @@ -49,24 +49,32 @@ class ExpressionSimplifier(object): simplifications_common.simp_ext_eq_ext, simplifications_common.simp_cmp_int, + simplifications_common.simp_sign_inf_zeroext, simplifications_common.simp_cmp_int_int, simplifications_common.simp_ext_cst, + simplifications_common.simp_zeroext_and_cst_eq_cst, + simplifications_common.simp_test_signext_inf, + simplifications_common.simp_test_zeroext_inf, ], m2_expr.ExprSlice: [ simplifications_common.simp_slice, simplifications_common.simp_slice_of_ext, + simplifications_common.simp_slice_of_op_ext, ], m2_expr.ExprCompose: [simplifications_common.simp_compose], m2_expr.ExprCond: [ simplifications_common.simp_cond, + simplifications_common.simp_cond_zeroext, # CC op simplifications_common.simp_cond_flag, simplifications_common.simp_cmp_int_arg, simplifications_common.simp_cond_eq_zero, - + simplifications_common.simp_x_and_cst_eq_cst, + simplifications_common.simp_cond_logic_ext, + simplifications_common.simp_cond_sign_bit, ], m2_expr.ExprMem: [simplifications_common.simp_mem], diff --git a/miasm2/expression/simplifications_common.py b/miasm2/expression/simplifications_common.py index 6f0eb34a..f7171091 100644 --- a/miasm2/expression/simplifications_common.py +++ b/miasm2/expression/simplifications_common.py @@ -73,12 +73,12 @@ def simp_cst_propagation(e_s, expr): out = int1.arg / int2.arg elif op_name == '%': out = int1.arg % int2.arg - elif op_name == 'idiv': + elif op_name == 'sdiv': assert int2.arg.arg tmp1 = mod_size2int[int1.arg.size](int1.arg) tmp2 = mod_size2int[int2.arg.size](int2.arg) out = mod_size2uint[int1.arg.size](tmp1 / tmp2) - elif op_name == 'imod': + elif op_name == 'smod': assert int2.arg.arg tmp1 = mod_size2int[int1.arg.size](int1.arg) tmp2 = mod_size2int[int2.arg.size](int2.arg) @@ -143,7 +143,7 @@ def simp_cst_propagation(e_s, expr): # op A => A if op_name in ['+', '*', '^', '&', '|', '>>', '<<', - 'a>>', '<<<', '>>>', 'idiv', 'imod', 'umod', 'udiv'] and len(args) == 1: + 'a>>', '<<<', '>>>', 'sdiv', 'smod', 'umod', 'udiv'] and len(args) == 1: return args[0] # A-B => A + (-B) @@ -382,7 +382,7 @@ def simp_cst_propagation(e_s, expr): return ExprOp(op_name, *args) -def simp_cond_op_int(e_s, expr): +def simp_cond_op_int(_, expr): "Extract conditions from operations" @@ -606,10 +606,11 @@ def simp_compose(e_s, expr): return ExprCompose(*args) -def simp_cond(e_s, expr): - "Common simplifications on ExprCond" - # eval exprcond src1/src2 with satifiable/unsatisfiable condition - # propagation +def simp_cond(_, expr): + """ + Common simplifications on ExprCond. + Eval exprcond src1/src2 with satifiable/unsatisfiable condition propagation + """ if (not expr.cond.is_int()) and expr.cond.size == 1: src1 = expr.src1.replace_expr({expr.cond: ExprInt(1, 1)}) src2 = expr.src2.replace_expr({expr.cond: ExprInt(0, 1)}) @@ -666,10 +667,11 @@ def simp_cond(e_s, expr): return expr -def simp_mem(e_s, expr): - "Common simplifications on ExprMem" - - # @32[x?a:b] => x?@32[a]:@32[b] +def simp_mem(_, expr): + """ + Common simplifications on ExprMem: + @32[x?a:b] => x?@32[a]:@32[b] + """ if expr.ptr.is_cond(): cond = expr.ptr ret = ExprCond(cond.cond, @@ -682,6 +684,15 @@ def simp_mem(e_s, expr): def test_cc_eq_args(expr, *sons_op): + """ + Return True if expression's arguments match the list in sons_op, and their + sub arguments are identical. Ex: + CC_S<=( + FLAG_SIGN_SUB(A, B), + FLAG_SUB_OF(A, B), + FLAG_EQ_CMP(A, B) + ) + """ if not expr.is_op(): return False if len(expr.args) != len(sons_op): @@ -694,7 +705,11 @@ def test_cc_eq_args(expr, *sons_op): return len(all_args) == 1 -def simp_cc_conds(expr_simp, expr): +def simp_cc_conds(_, expr): + """ + High level simplifications. Example: + CC_U<(FLAG_SUB_CF(A, B) => A <u B + """ if (expr.is_op("CC_U>=") and test_cc_eq_args( expr, @@ -702,8 +717,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp(TOK_INF_UNSIGNED, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1)) + ExprInt(0, expr.size), + ExprInt(1, expr.size)) elif (expr.is_op("CC_U<") and test_cc_eq_args( @@ -726,8 +741,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp(TOK_INF_SIGNED, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_EQ") and @@ -746,8 +761,8 @@ def simp_cc_conds(expr_simp, expr): arg = expr.args[0].args[0] expr = ExprCond( ExprOp(TOK_EQUAL,arg, ExprInt(0, arg.size)), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_NE") and test_cc_eq_args( @@ -756,8 +771,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp(TOK_EQUAL, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_EQ") and @@ -781,8 +796,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp("&", *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_S>") and @@ -794,8 +809,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp(TOK_INF_EQUAL_SIGNED, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_S>") and @@ -806,8 +821,8 @@ def simp_cc_conds(expr_simp, expr): expr.args[1].is_int(0)): expr = ExprCond( ExprOp(TOK_INF_EQUAL_SIGNED, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) @@ -820,8 +835,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp(TOK_INF_SIGNED, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_S<") and @@ -865,8 +880,8 @@ def simp_cc_conds(expr_simp, expr): )): expr = ExprCond( ExprOp(TOK_INF_EQUAL_UNSIGNED, *expr.args[0].args), - ExprInt(0, 1), - ExprInt(1, 1) + ExprInt(0, expr.size), + ExprInt(1, expr.size) ) elif (expr.is_op("CC_S<") and @@ -882,8 +897,8 @@ def simp_cc_conds(expr_simp, expr): -def simp_cond_flag(expr_simp, expr): - # FLAG_EQ_CMP(X, Y)?A:B => (X == Y)?A:B +def simp_cond_flag(_, expr): + """FLAG_EQ_CMP(X, Y)?A:B => (X == Y)?A:B""" cond = expr.cond if cond.is_op("FLAG_EQ_CMP"): return ExprCond(ExprOp(TOK_EQUAL, *cond.args), expr.src1, expr.src2) @@ -891,8 +906,10 @@ def simp_cond_flag(expr_simp, expr): def simp_cmp_int(expr_simp, expr): - # ({X, 0} == int) => X == int[:] - # X + int1 == int2 => X == int2-int1 + """ + ({X, 0} == int) => X == int[:] + X + int1 == int2 => X == int2-int1 + """ if (expr.is_op(TOK_EQUAL) and expr.args[1].is_int() and expr.args[0].is_compose() and @@ -931,7 +948,7 @@ def simp_cmp_int(expr_simp, expr): -def simp_cmp_int_arg(expr_simp, expr): +def simp_cmp_int_arg(_, expr): """ (0x10 <= R0) ? A:B => @@ -971,10 +988,8 @@ def simp_cmp_int_arg(expr_simp, expr): return ExprCond(ExprOp(op, arg1, arg2), src1, src2) - - -def simp_subwc_cf(expr_s, expr): - # SUBWC_CF(A, B, SUB_CF(C, D)) => SUB_CF({A, C}, {B, D}) +def simp_subwc_cf(_, expr): + """SUBWC_CF(A, B, SUB_CF(C, D)) => SUB_CF({A, C}, {B, D})""" if not expr.is_op('FLAG_SUBWC_CF'): return expr op3 = expr.args[2] @@ -987,8 +1002,8 @@ def simp_subwc_cf(expr_s, expr): return ExprOp("FLAG_SUB_CF", op1, op2) -def simp_subwc_of(expr_s, expr): - # SUBWC_OF(A, B, SUB_CF(C, D)) => SUB_OF({A, C}, {B, D}) +def simp_subwc_of(_, expr): + """SUBWC_OF(A, B, SUB_CF(C, D)) => SUB_OF({A, C}, {B, D})""" if not expr.is_op('FLAG_SUBWC_OF'): return expr op3 = expr.args[2] @@ -1001,8 +1016,8 @@ def simp_subwc_of(expr_s, expr): return ExprOp("FLAG_SUB_OF", op1, op2) -def simp_sign_subwc_cf(expr_s, expr): - # SIGN_SUBWC(A, B, SUB_CF(C, D)) => SIGN_SUB({A, C}, {B, D}) +def simp_sign_subwc_cf(_, expr): + """SIGN_SUBWC(A, B, SUB_CF(C, D)) => SIGN_SUB({A, C}, {B, D})""" if not expr.is_op('FLAG_SIGN_SUBWC'): return expr op3 = expr.args[2] @@ -1014,8 +1029,8 @@ def simp_sign_subwc_cf(expr_s, expr): return ExprOp("FLAG_SIGN_SUB", op1, op2) -def simp_double_zeroext(expr_s, expr): - # A.zeroExt(X).zeroExt(Y) => A.zeroExt(Y) +def simp_double_zeroext(_, expr): + """A.zeroExt(X).zeroExt(Y) => A.zeroExt(Y)""" if not (expr.is_op() and expr.op.startswith("zeroExt")): return expr arg1 = expr.args[0] @@ -1024,8 +1039,8 @@ def simp_double_zeroext(expr_s, expr): arg2 = arg1.args[0] return ExprOp(expr.op, arg2) -def simp_double_signext(expr_s, expr): - # A.signExt(X).signExt(Y) => A.signExt(Y) +def simp_double_signext(_, expr): + """A.signExt(X).signExt(Y) => A.signExt(Y)""" if not (expr.is_op() and expr.op.startswith("signExt")): return expr arg1 = expr.args[0] @@ -1034,8 +1049,8 @@ def simp_double_signext(expr_s, expr): arg2 = arg1.args[0] return ExprOp(expr.op, arg2) -def simp_zeroext_eq_cst(expr_s, expr): - # A.zeroExt(X) == int => A == int[:A.size] +def simp_zeroext_eq_cst(_, expr): + """A.zeroExt(X) == int => A == int[:A.size]""" if not expr.is_op(TOK_EQUAL): return expr arg1, arg2 = expr.args @@ -1046,12 +1061,31 @@ def simp_zeroext_eq_cst(expr_s, expr): src = arg1.args[0] if int(arg2) > (1 << src.size): # Always false - return ExprInt(0, 1) + return ExprInt(0, expr.size) return ExprOp(TOK_EQUAL, src, ExprInt(int(arg2), src.size)) -def simp_ext_eq_ext(expr_s, expr): - # A.zeroExt(X) == B.zeroExt(X) => A == B - # A.signExt(X) == B.signExt(X) => A == B +def simp_cond_zeroext(_, expr): + """ + X.zeroExt()?(A:B) => X ? A:B + X.signExt()?(A:B) => X ? A:B + """ + if not ( + expr.cond.is_op() and + ( + expr.cond.op.startswith("zeroExt") or + expr.cond.op.startswith("signExt") + ) + ): + return expr + + ret = ExprCond(expr.cond.args[0], expr.src1, expr.src2) + return ret + +def simp_ext_eq_ext(_, expr): + """ + A.zeroExt(X) == B.zeroExt(X) => A == B + A.signExt(X) == B.signExt(X) => A == B + """ if not expr.is_op(TOK_EQUAL): return expr arg1, arg2 = expr.args @@ -1064,8 +1098,8 @@ def simp_ext_eq_ext(expr_s, expr): return expr return ExprOp(TOK_EQUAL, arg1.args[0], arg2.args[0]) -def simp_cond_eq_zero(expr_s, expr): - # (X == 0)?(A:B) => X?(B:A) +def simp_cond_eq_zero(_, expr): + """(X == 0)?(A:B) => X?(B:A)""" cond = expr.cond if not cond.is_op(TOK_EQUAL): return expr @@ -1075,13 +1109,122 @@ def simp_cond_eq_zero(expr_s, expr): new_expr = ExprCond(arg1, expr.src2, expr.src1) return new_expr +def simp_sign_inf_zeroext(expr_s, expr): + """ + /!\ Ensure before: X.zeroExt(X.size) => X + + X.zeroExt() <s 0 => 0 + X.zeroExt() <=s 0 => X == 0 -def simp_cmp_int_int(expr_s, expr): - # IntA <s IntB => int - # IntA <u IntB => int - # IntA <=s IntB => int - # IntA <=u IntB => int - # IntA == IntB => int + X.zeroExt() <s cst => X.zeroExt() <u cst (cst positive) + X.zeroExt() <=s cst => X.zeroExt() <=u cst (cst positive) + + X.zeroExt() <s cst => 0 (cst negative) + X.zeroExt() <=s cst => 0 (cst negative) + + """ + if not (expr.is_op(TOK_INF_SIGNED) or expr.is_op(TOK_INF_EQUAL_SIGNED)): + return expr + arg1, arg2 = expr.args + if not arg2.is_int(): + return expr + if not (arg1.is_op() and arg1.op.startswith("zeroExt")): + return expr + src = arg1.args[0] + assert src.size < arg1.size + + # If cst is zero + if arg2.is_int(0): + if expr.is_op(TOK_INF_SIGNED): + # X.zeroExt() <s 0 => 0 + return ExprInt(0, expr.size) + else: + # X.zeroExt() <=s 0 => X == 0 + return ExprOp(TOK_EQUAL, src, ExprInt(0, src.size)) + + # cst is not zero + cst = int(arg2) + if cst & (1 << (arg2.size - 1)): + # cst is negative + return ExprInt(0, expr.size) + # cst is positive + if expr.is_op(TOK_INF_SIGNED): + # X.zeroExt() <s cst => X.zeroExt() <u cst (cst positive) + return ExprOp(TOK_INF_UNSIGNED, src, expr_s(arg2[:src.size])) + # X.zeroExt() <=s cst => X.zeroExt() <=u cst (cst positive) + return ExprOp(TOK_INF_EQUAL_UNSIGNED, src, expr_s(arg2[:src.size])) + + +def simp_zeroext_and_cst_eq_cst(expr_s, expr): + """ + A.zeroExt(X) & ... & int == int => A & ... & int[:A.size] == int[:A.size] + """ + if not expr.is_op(TOK_EQUAL): + return expr + arg1, arg2 = expr.args + if not arg2.is_int(): + return expr + if not arg1.is_op('&'): + return expr + is_ok = True + sizes = set() + for arg in arg1.args: + if arg.is_int(): + continue + if (arg.is_op() and + arg.op.startswith("zeroExt")): + sizes.add(arg.args[0].size) + continue + is_ok = False + break + if not is_ok: + return expr + if len(sizes) != 1: + return expr + size = list(sizes)[0] + if int(arg2) > ((1 << size) - 1): + return expr + args = [expr_s(arg[:size]) for arg in arg1.args] + left = ExprOp('&', *args) + right = expr_s(arg2[:size]) + ret = ExprOp(TOK_EQUAL, left, right) + return ret + + +def test_one_bit_set(arg): + """ + Return True if arg has form 1 << X + """ + return arg != 0 and ((arg & (arg - 1)) == 0) + +def simp_x_and_cst_eq_cst(_, expr): + """ + (x & ... & onebitmask == onebitmask) ? A:B => (x & ... & onebitmask) ? A:B + """ + cond = expr.cond + if not cond.is_op(TOK_EQUAL): + return expr + arg1, mask2 = cond.args + if not mask2.is_int(): + return expr + if not test_one_bit_set(int(mask2)): + return expr + if not arg1.is_op('&'): + return expr + mask1 = arg1.args[-1] + if mask1 != mask2: + return expr + cond = ExprOp('&', *arg1.args) + return ExprCond(cond, expr.src1, expr.src2) + +def simp_cmp_int_int(_, expr): + """ + IntA <s IntB => int + IntA <u IntB => int + IntA <=s IntB => int + IntA <=u IntB => int + IntA == IntB => int + """ if expr.op not in [ TOK_EQUAL, TOK_INF_SIGNED, TOK_INF_UNSIGNED, @@ -1094,8 +1237,7 @@ def simp_cmp_int_int(expr_s, expr): if expr.is_op(TOK_EQUAL): if int_a == int_b: return ExprInt(1, 1) - else: - return ExprInt(0, 1) + return ExprInt(0, expr.size) if expr.op in [TOK_INF_SIGNED, TOK_INF_EQUAL_SIGNED]: int_a = int(mod_size2int[int_a.size](int(int_a))) @@ -1116,9 +1258,11 @@ def simp_cmp_int_int(expr_s, expr): return ExprInt(ret, 1) -def simp_ext_cst(expr_s, expr): - # Int.zeroExt(X) => Int - # Int.signExt(X) => Int +def simp_ext_cst(_, expr): + """ + Int.zeroExt(X) => Int + Int.signExt(X) => Int + """ if not (expr.op.startswith("zeroExt") or expr.op.startswith("signExt")): return expr arg = expr.args[0] @@ -1132,31 +1276,150 @@ def simp_ext_cst(expr_s, expr): return ret -def simp_slice_of_ext(expr_s, expr): - # zeroExt(X)[0:size(X)] => X - if expr.start != 0: - return expr +def simp_slice_of_ext(_, expr): + """ + C.zeroExt(X)[A:B] => 0 if A >= size(C) + C.zeroExt(X)[A:B] => C[A:B] if B <= size(C) + A.zeroExt(X)[0:Y] => A.zeroExt(Y) + """ if not expr.arg.is_op(): return expr if not expr.arg.op.startswith("zeroExt"): return expr arg = expr.arg.args[0] - if arg.size != expr.size: + + if expr.start >= arg.size: + # C.zeroExt(X)[A:B] => 0 if A >= size(C) + return ExprInt(0, expr.size) + if expr.stop <= arg.size: + # C.zeroExt(X)[A:B] => C[A:B] if B <= size(C) + return arg[expr.start:expr.stop] + if expr.start == 0: + # A.zeroExt(X)[0:Y] => A.zeroExt(Y) + return arg.zeroExtend(expr.stop) + return expr + +def simp_slice_of_op_ext(expr_s, expr): + """(X.zeroExt() + ... + Int)[0:8] => X + ... + int[:]""" + if expr.start != 0: + return expr + src = expr.arg + if not src.is_op("+"): + return expr + is_ok = True + for arg in src.args: + if arg.is_int(): + continue + if (arg.is_op() and + arg.op.startswith("zeroExt") and + arg.args[0].size == expr.stop): + continue + is_ok = False + break + if not is_ok: + return expr + args = [expr_s(arg[:expr.stop]) for arg in src.args] + return ExprOp("+", *args) + + +def simp_cond_logic_ext(expr_s, expr): + """(X.zeroExt() + ... + Int) ? A:B => X + ... + int[:] ? A:B""" + cond = expr.cond + if not cond.is_op(): + return expr + if cond.op not in ["&", "^", "|"]: + return expr + is_ok = True + sizes = set() + for arg in cond.args: + if arg.is_int(): + continue + if (arg.is_op() and + arg.op.startswith("zeroExt")): + sizes.add(arg.args[0].size) + continue + is_ok = False + break + if not is_ok: + return expr + if len(sizes) != 1: + return expr + size = list(sizes)[0] + args = [expr_s(arg[:size]) for arg in cond.args] + cond = ExprOp(cond.op, *args) + return ExprCond(cond, expr.src1, expr.src2) + + +def simp_cond_sign_bit(_, expr): + """(a & .. & 0x80000000) ? A:B => (a & ...) <s 0 ? A:B""" + cond = expr.cond + if not cond.is_op('&'): + return expr + last = cond.args[-1] + if not last.is_int(1 << (last.size - 1)): + return expr + zero = ExprInt(0, expr.cond.size) + if len(cond.args) == 2: + args = [cond.args[0], zero] + else: + args = [ExprOp('&', *list(cond.args[:-1])), zero] + cond = ExprOp(TOK_INF_SIGNED, *args) + return ExprCond(cond, expr.src1, expr.src2) + + +def simp_test_signext_inf(expr_s, expr): + """A.signExt() <s int => A <s int[:]""" + if not (expr.is_op(TOK_INF_SIGNED) or expr.is_op(TOK_INF_EQUAL_SIGNED)): + return expr + arg, cst = expr.args + if not (arg.is_op() and arg.op.startswith("signExt")): return expr - return arg + if not cst.is_int(): + return expr + base = arg.args[0] + tmp = int(mod_size2int[cst.size](int(cst))) + if -(1 << (base.size - 1)) <= tmp < (1 << (base.size - 1)): + # Can trunc integer + return ExprOp(expr.op, base, expr_s(cst[:base.size])) + if (tmp >= (1 << (base.size - 1)) or + tmp < -(1 << (base.size - 1)) ): + return ExprInt(1, 1) + return expr -def simp_add_multiple(expr_s, expr): - # X + X => 2 * X - # X + X * int1 => X * (1 + int1) - # X * int1 + (- X) => X * (int1 - 1) - # X + (X << int1) => X * (1 + 2 ** int1) - # Correct even if addition overflow/underflow + +def simp_test_zeroext_inf(expr_s, expr): + """A.zeroExt() <u int => A <u int[:]""" + if not (expr.is_op(TOK_INF_UNSIGNED) or expr.is_op(TOK_INF_EQUAL_UNSIGNED)): + return expr + arg, cst = expr.args + if not (arg.is_op() and arg.op.startswith("zeroExt")): + return expr + if not cst.is_int(): + return expr + base = arg.args[0] + tmp = int(mod_size2uint[cst.size](int(cst))) + if 0 <= tmp < (1 << base.size): + # Can trunc integer + return ExprOp(expr.op, base, expr_s(cst[:base.size])) + if tmp >= (1 << base.size): + return ExprInt(1, 1) + return expr + + +def simp_add_multiple(_, expr): + """ + X + X => 2 * X + X + X * int1 => X * (1 + int1) + X * int1 + (- X) => X * (int1 - 1) + X + (X << int1) => X * (1 + 2 ** int1) + Correct even if addition overflow/underflow + """ if not expr.is_op('+'): return expr # Extract each argument and its counter operands = {} - for i, arg in enumerate(expr.args): + for arg in expr.args: if arg.is_op('*') and arg.args[1].is_int(): base_expr, factor = arg.args operands[base_expr] = operands.get(base_expr, 0) + int(factor) diff --git a/miasm2/ir/translators/C.py b/miasm2/ir/translators/C.py index a5453745..a239383b 100644 --- a/miasm2/ir/translators/C.py +++ b/miasm2/ir/translators/C.py @@ -372,7 +372,7 @@ class TranslatorC(Translator): - elif expr.op in ['idiv', 'imod']: + elif expr.op in ['sdiv', 'smod']: arg0 = self.from_expr(expr.args[0]) arg1 = self.from_expr(expr.args[1]) diff --git a/miasm2/ir/translators/smt2.py b/miasm2/ir/translators/smt2.py index eda24bb7..81d86798 100644 --- a/miasm2/ir/translators/smt2.py +++ b/miasm2/ir/translators/smt2.py @@ -198,13 +198,13 @@ class TranslatorSMT2(Translator): res = bvmul(res, arg) elif expr.op == "/": res = bvsdiv(res, arg) - elif expr.op == "idiv": + elif expr.op == "sdiv": res = bvsdiv(res, arg) elif expr.op == "udiv": res = bvudiv(res, arg) elif expr.op == "%": res = bvsmod(res, arg) - elif expr.op == "imod": + elif expr.op == "smod": res = bvsmod(res, arg) elif expr.op == "umod": res = bvurem(res, arg) diff --git a/miasm2/ir/translators/z3_ir.py b/miasm2/ir/translators/z3_ir.py index d43468ef..2572ac74 100644 --- a/miasm2/ir/translators/z3_ir.py +++ b/miasm2/ir/translators/z3_ir.py @@ -171,7 +171,7 @@ class TranslatorZ3(Translator): def _abs(self, z3_value): return z3.If(z3_value >= 0,z3_value,-z3_value) - def _idivC(self, num, den): + def _sdivC(self, num, den): """Divide (signed) @num by @den (z3 values) as C would See modint.__div__ for implementation choice """ @@ -197,12 +197,12 @@ class TranslatorZ3(Translator): res = z3.RotateLeft(res, arg) elif expr.op == ">>>": res = z3.RotateRight(res, arg) - elif expr.op == "idiv": - res = self._idivC(res, arg) + elif expr.op == "sdiv": + res = self._sdivC(res, arg) elif expr.op == "udiv": res = z3.UDiv(res, arg) - elif expr.op == "imod": - res = res - (arg * (self._idivC(res, arg))) + elif expr.op == "smod": + res = res - (arg * (self._sdivC(res, arg))) elif expr.op == "umod": res = z3.URem(res, arg) elif expr.op == "==": diff --git a/miasm2/jitter/bn.c b/miasm2/jitter/bn.c index 96e66f4d..c621d102 100644 --- a/miasm2/jitter/bn.c +++ b/miasm2/jitter/bn.c @@ -796,7 +796,7 @@ int bignum_cnttrailzeros(bn_t n, int size) -bn_t bignum_idiv(bn_t a, bn_t b, int size) +bn_t bignum_sdiv(bn_t a, bn_t b, int size) { require(size, "size must be greater than 0"); require(size <= BN_BIT_SIZE, "size must be below bignum max size"); @@ -832,14 +832,14 @@ bn_t bignum_idiv(bn_t a, bn_t b, int size) -bn_t bignum_imod(bn_t a, bn_t b, int size) +bn_t bignum_smod(bn_t a, bn_t b, int size) { require(size, "size must be greater than 0"); require(size <= BN_BIT_SIZE, "size must be below bignum max size"); bn_t c; - c = bignum_idiv(a, b, size); + c = bignum_sdiv(a, b, size); c = bignum_mul(c, b); c = bignum_sub(a, c); c = bignum_mask(c, size); diff --git a/miasm2/jitter/bn.h b/miasm2/jitter/bn.h index 67d20a77..f0a13b53 100644 --- a/miasm2/jitter/bn.h +++ b/miasm2/jitter/bn.h @@ -116,8 +116,8 @@ _MIASM_EXPORT bn_t bignum_sub(bn_t a, bn_t b); /* c = a - b */ _MIASM_EXPORT bn_t bignum_mul(bn_t a, bn_t b); /* c = a * b */ _MIASM_EXPORT bn_t bignum_udiv(bn_t a, bn_t b); /* c = a / b */ _MIASM_EXPORT bn_t bignum_umod(bn_t a, bn_t b); /* c = a % b */ -_MIASM_EXPORT bn_t bignum_idiv(bn_t a, bn_t b, int size); -_MIASM_EXPORT bn_t bignum_imod(bn_t a, bn_t b, int size); +_MIASM_EXPORT bn_t bignum_sdiv(bn_t a, bn_t b, int size); +_MIASM_EXPORT bn_t bignum_smod(bn_t a, bn_t b, int size); //void bignum_udivmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */ diff --git a/miasm2/jitter/jitcore.py b/miasm2/jitter/jitcore.py index fc5cf35e..78e27244 100644 --- a/miasm2/jitter/jitcore.py +++ b/miasm2/jitter/jitcore.py @@ -114,21 +114,11 @@ class JitCore(object): for a, b in self.blocks_mem_interval: vm.add_code_bloc(a, b + 1) - def jit_irblocks(self, label, irblocks): - """JiT a group of irblocks. - @label: the label of the irblocks - @irblocks: a group of irblocks - """ - - raise NotImplementedError("Abstract class") - def add_block(self, block): """Add a block to JiT and JiT it. @block: asm_bloc to add """ - irblocks = self.ir_arch.add_asmblock_to_ircfg(block, self.ircfg, gen_pc_updt = True) - block.blocks = irblocks - self.jit_irblocks(block.loc_key, irblocks) + raise NotImplementedError("Abstract class") def disasm_and_jit_block(self, addr, vm): """Disassemble a new block and JiT it diff --git a/miasm2/jitter/jitcore_python.py b/miasm2/jitter/jitcore_python.py index 0b1f5809..fdd5c2ae 100644 --- a/miasm2/jitter/jitcore_python.py +++ b/miasm2/jitter/jitcore_python.py @@ -1,5 +1,5 @@ import miasm2.jitter.jitcore as jitcore -import miasm2.expression.expression as m2_expr +from miasm2.expression.expression import ExprInt, ExprLoc import miasm2.jitter.csts as csts from miasm2.expression.simplifications import expr_simp_explicit from miasm2.jitter.emulatedsymbexec import EmulatedSymbExec @@ -36,12 +36,38 @@ class JitCore_Python(jitcore.JitCore): "Preload symbols according to current architecture" self.symbexec.reset_regs() - def jit_irblocks(self, loc_key, irblocks): - """Create a python function corresponding to an irblocks' group. - @loc_key: the loc_key of the irblocks - @irblocks: a group of irblocks + def arch_specific(self): + """Return arch specific information for the current architecture""" + arch = self.ir_arch.arch + has_delayslot = False + if arch.name == "mips32": + from miasm2.arch.mips32.jit import mipsCGen + cgen_class = mipsCGen + has_delayslot = True + elif arch.name == "arm": + from miasm2.arch.arm.jit import arm_CGen + cgen_class = arm_CGen + else: + from miasm2.jitter.codegen import CGen + cgen_class = CGen + return cgen_class(self.ir_arch), has_delayslot + + def add_block(self, asmblock): + """Create a python function corresponding to an AsmBlock + @asmblock: AsmBlock """ + # TODO: merge duplicate code with CGen, llvmconvert + codegen, has_delayslot = self.arch_specific() + irblocks_list = codegen.block2assignblks(asmblock) + instr_offsets = [line.offset for line in asmblock.lines] + + loc_db = self.ir_arch.loc_db + local_loc_keys = [] + for irblocks in irblocks_list: + for irblock in irblocks: + local_loc_keys.append(irblock.loc_key) + def myfunc(cpu): """Execute the function according to cpu and vmmngr states @cpu: JitCpu instance @@ -49,86 +75,131 @@ class JitCore_Python(jitcore.JitCore): # Get virtual memory handler vmmngr = cpu.vmmngr - # Keep current location in irblocks - cur_loc_key = loc_key - - # Required to detect new instructions - offsets_jitted = set() - - # Get exec engine + # Get execution engine (EmulatedSymbExec instance) exec_engine = self.symbexec - expr_simp = exec_engine.expr_simp - # For each irbloc inside irblocks - while True: - # Get the current bloc - for irb in irblocks: - if irb.loc_key == cur_loc_key: - break + # Refresh CPU values according to @cpu instance + exec_engine.update_engine_from_cpu() - else: - raise RuntimeError("Irblocks must end with returning an " - "ExprInt instance") - - # Refresh CPU values according to @cpu instance - exec_engine.update_engine_from_cpu() - - # Execute current ir bloc - for assignblk in irb: - instr = assignblk.instr - # For each new instruction (in assembly) - if instr is not None and instr.offset not in offsets_jitted: - # Test exceptions - vmmngr.check_invalid_code_blocs() - vmmngr.check_memory_breakpoint() - if vmmngr.get_exception(): - exec_engine.update_cpu_from_engine() - return instr.offset + # Get initial loc_key + cur_loc_key = asmblock.loc_key - offsets_jitted.add(instr.offset) + # Update PC helper + update_pc = lambda value: setattr(cpu, self.ir_arch.pc.name, value) - # Log registers values - if self.log_regs: - exec_engine.update_cpu_from_engine() - exec_engine.cpu.dump_gpregs_with_attrib(self.ir_arch.attrib) + while True: + # Retrieve the expected irblock + for instr, irblocks in zip(asmblock.lines, irblocks_list): + for index, irblock in enumerate(irblocks): + if irblock.loc_key == cur_loc_key: + break + else: + continue + break + else: + raise RuntimeError("Unable to find the block for %r" % cur_loc_key) + + instr_attrib, irblocks_attributes = codegen.get_attributes( + instr, irblocks, self.log_mn, self.log_regs + ) + irblock_attributes = irblocks_attributes[index] + + # Do IRBlock + new_irblock = self.ir_arch.irbloc_fix_regs_for_mode( + irblock, self.ir_arch.attrib + ) + if index == 0: + # Pre code + if instr_attrib.log_mn: + print "%.8X %s" % ( + instr_attrib.instr.offset, + instr_attrib.instr.to_string(loc_db) + ) + + # Exec IRBlock + instr = instr_attrib.instr + + for index, assignblk in enumerate(irblock): + attributes = irblock_attributes[index] - # Log instruction - if self.log_mn: - print "%08x %s" % (instr.offset, instr) + # Eval current instruction (in IR) + exec_engine.eval_updt_assignblk(assignblk) - # Check for exception - if (vmmngr.get_exception() != 0 or - cpu.get_exception() != 0): - exec_engine.update_cpu_from_engine() + # Check memory access / write exception + # TODO: insert a check between memory reads and writes + if attributes.mem_read or attributes.mem_write: + # Restricted exception + flag = ~csts.EXCEPT_CODE_AUTOMOD & csts.EXCEPT_DO_NOT_UPDATE_PC + if (vmmngr.get_exception() & flag != 0): + # Do not update registers + update_pc(instr.offset) return instr.offset - # Eval current instruction (in IR) - exec_engine.eval_updt_assignblk(assignblk) - # Check for exceptions which do not update PC + # Update registers values exec_engine.update_cpu_from_engine() - if (vmmngr.get_exception() & csts.EXCEPT_DO_NOT_UPDATE_PC != 0 or - cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP): - return instr.offset - - vmmngr.check_invalid_code_blocs() - vmmngr.check_memory_breakpoint() - # Get next bloc address - ad = expr_simp(exec_engine.eval_expr(self.ir_arch.IRDst)) + # Check post assignblk exception flags + if attributes.set_exception: + # Restricted exception + if cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP: + # Update PC + update_pc(instr.offset) + return instr.offset - # Updates @cpu instance according to new CPU values - exec_engine.update_cpu_from_engine() + dst = exec_engine.eval_expr(self.ir_arch.IRDst) + if dst.is_int(): + loc_key = loc_db.get_or_create_offset_location(int(dst)) + dst = ExprLoc(loc_key, dst.size) + + assert dst.is_loc() + loc_key = dst.loc_key + offset = loc_db.get_location_offset(loc_key) + if offset is None: + # Avoid checks on generated label + cur_loc_key = loc_key + continue + + if instr_attrib.log_regs: + update_pc(offset) + cpu.dump_gpregs_with_attrib(self.ir_arch.attrib) + + # Post-instr checks + if instr_attrib.mem_read | instr_attrib.mem_write: + vmmngr.check_memory_breakpoint() + vmmngr.check_invalid_code_blocs() + if vmmngr.get_exception(): + update_pc(offset) + return offset + + if instr_attrib.set_exception: + if cpu.get_exception(): + update_pc(offset) + return offset + + if instr_attrib.mem_read | instr_attrib.mem_write: + vmmngr.reset_memory_access() # Manage resulting address - if isinstance(ad, m2_expr.ExprInt): - return ad.arg.arg - elif isinstance(ad, m2_expr.ExprLoc): - cur_loc_key = ad.loc_key - else: - raise NotImplementedError("Type not handled: %s" % ad) + if (loc_key in local_loc_keys and + offset > instr.offset): + # Forward local jump + # Note: a backward local jump has to be promoted to extern, + # for max_exec_per_call support + cur_loc_key = loc_key + continue + + # Delay slot + if has_delayslot: + delay_slot_set = exec_engine.eval_expr(codegen.delay_slot_set) + if delay_slot_set.is_int() and int(delay_slot_set) != 0: + return int(exec_engine.eval_expr(codegen.delay_slot_dst)) + + # Extern of asmblock, must have an offset + assert offset is not None + return offset # Associate myfunc with current loc_key - offset = self.ir_arch.loc_db.get_location_offset(loc_key) + offset = loc_db.get_location_offset(asmblock.loc_key) assert offset is not None self.offset_to_jitted_func[offset] = myfunc diff --git a/miasm2/jitter/llvmconvert.py b/miasm2/jitter/llvmconvert.py index 37ce8d52..41461c3a 100644 --- a/miasm2/jitter/llvmconvert.py +++ b/miasm2/jitter/llvmconvert.py @@ -874,15 +874,15 @@ class LLVMFunction(object): self.update_cache(expr, ret) return ret - if op in ["imod", "idiv", "umod", "udiv"]: + if op in ["smod", "sdiv", "umod", "udiv"]: assert len(expr.args) == 2 arg_b = self.add_ir(expr.args[1]) arg_a = self.add_ir(expr.args[0]) - if op == "imod": + if op == "smod": callback = builder.srem - elif op == "idiv": + elif op == "sdiv": callback = builder.sdiv elif op == "umod": callback = builder.urem @@ -1297,7 +1297,7 @@ class LLVMFunction(object): # Update PC for dump_gpregs PC = self.llvm_context.PC t_size = LLVMType.IntType(PC.size) - dst = self.builder.zext(t_size(pc_value), LLVMType.IntType(PC.size)) + dst = self.builder.zext(t_size(pc_value), t_size) self.affect(dst, PC) fc_ptr = self.mod.get_global(self.llvm_context.logging_func) diff --git a/miasm2/jitter/op_semantics.c b/miasm2/jitter/op_semantics.c index 091da87f..46e6cca1 100644 --- a/miasm2/jitter/op_semantics.c +++ b/miasm2/jitter/op_semantics.c @@ -738,12 +738,12 @@ UMOD(16) UMOD(32) UMOD(64) -IDIV(8) -IDIV(16) -IDIV(32) -IDIV(64) - -IMOD(8) -IMOD(16) -IMOD(32) -IMOD(64) +SDIV(8) +SDIV(16) +SDIV(32) +SDIV(64) + +SMOD(8) +SMOD(16) +SMOD(32) +SMOD(64) diff --git a/miasm2/jitter/op_semantics.h b/miasm2/jitter/op_semantics.h index 921c9b9e..690cfb35 100644 --- a/miasm2/jitter/op_semantics.h +++ b/miasm2/jitter/op_semantics.h @@ -66,8 +66,8 @@ _MIASM_EXPORT unsigned int cnttrailzeros(uint64_t size, uint64_t src); } -#define IDIV(sizeA) \ - int ## sizeA ## _t idiv ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \ +#define SDIV(sizeA) \ + int ## sizeA ## _t sdiv ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \ { \ int ## sizeA ## _t r; \ if (b == 0) { \ @@ -79,8 +79,8 @@ _MIASM_EXPORT unsigned int cnttrailzeros(uint64_t size, uint64_t src); } -#define IMOD(sizeA) \ - int ## sizeA ## _t imod ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \ +#define SMOD(sizeA) \ + int ## sizeA ## _t smod ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \ { \ int ## sizeA ## _t r; \ if (b == 0) { \ @@ -93,23 +93,23 @@ _MIASM_EXPORT unsigned int cnttrailzeros(uint64_t size, uint64_t src); _MIASM_EXPORT uint64_t udiv64(uint64_t a, uint64_t b); _MIASM_EXPORT uint64_t umod64(uint64_t a, uint64_t b); -_MIASM_EXPORT int64_t idiv64(int64_t a, int64_t b); -_MIASM_EXPORT int64_t imod64(int64_t a, int64_t b); +_MIASM_EXPORT int64_t sdiv64(int64_t a, int64_t b); +_MIASM_EXPORT int64_t smod64(int64_t a, int64_t b); _MIASM_EXPORT uint32_t udiv32(uint32_t a, uint32_t b); _MIASM_EXPORT uint32_t umod32(uint32_t a, uint32_t b); -_MIASM_EXPORT int32_t idiv32(int32_t a, int32_t b); -_MIASM_EXPORT int32_t imod32(int32_t a, int32_t b); +_MIASM_EXPORT int32_t sdiv32(int32_t a, int32_t b); +_MIASM_EXPORT int32_t smod32(int32_t a, int32_t b); _MIASM_EXPORT uint16_t udiv16(uint16_t a, uint16_t b); _MIASM_EXPORT uint16_t umod16(uint16_t a, uint16_t b); -_MIASM_EXPORT int16_t idiv16(int16_t a, int16_t b); -_MIASM_EXPORT int16_t imod16(int16_t a, int16_t b); +_MIASM_EXPORT int16_t sdiv16(int16_t a, int16_t b); +_MIASM_EXPORT int16_t smod16(int16_t a, int16_t b); _MIASM_EXPORT uint8_t udiv8(uint8_t a, uint8_t b); _MIASM_EXPORT uint8_t umod8(uint8_t a, uint8_t b); -_MIASM_EXPORT int8_t idiv8(int8_t a, int8_t b); -_MIASM_EXPORT int8_t imod8(int8_t a, int8_t b); +_MIASM_EXPORT int8_t sdiv8(int8_t a, int8_t b); +_MIASM_EXPORT int8_t smod8(int8_t a, int8_t b); _MIASM_EXPORT unsigned int x86_cpuid(unsigned int a, unsigned int reg_num); |