about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/expression/expression.py182
-rw-r--r--test/expression/expr_cmp.py107
-rwxr-xr-xtest/test_all.py1
3 files changed, 290 insertions, 0 deletions
diff --git a/miasm2/expression/expression.py b/miasm2/expression/expression.py
index b7b90470..591dc024 100644
--- a/miasm2/expression/expression.py
+++ b/miasm2/expression/expression.py
@@ -1538,3 +1538,185 @@ def get_expr_mem(expr):
     ops = set()
     expr.visit(lambda x: visit_getmem(x, ops))
     return ops
+
+
+def _expr_compute_cf(op1, op2):
+    """
+    Get carry flag of @op1 - @op2
+    Ref: x86 cf flag
+    @op1: Expression
+    @op2: Expression
+    """
+    res = op1 - op2
+    cf = (((op1 ^ op2) ^ res) ^ ((op1 ^ res) & (op1 ^ op2))).msb()
+    return cf
+
+def _expr_compute_of(op1, op2):
+    """
+    Get overflow flag of @op1 - @op2
+    Ref: x86 of flag
+    @op1: Expression
+    @op2: Expression
+    """
+    res = op1 - op2
+    of = (((op1 ^ res) & (op1 ^ op2))).msb()
+    return of
+
+def _expr_compute_zf(op1, op2):
+    """
+    Get zero flag of @op1 - @op2
+    @op1: Expression
+    @op2: Expression
+    """
+    res = op1 - op2
+    zf = ExprCond(res,
+                  ExprInt(0, 1),
+                  ExprInt(1, 1))
+    return zf
+
+
+def _expr_compute_nf(op1, op2):
+    """
+    Get negative (or sign) flag of @op1 - @op2
+    @op1: Expression
+    @op2: Expression
+    """
+    res = op1 - op2
+    nf = res.msb()
+    return nf
+
+
+def expr_is_equal(op1, op2):
+    """
+    if op1 == op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    zf = _expr_compute_zf(op1, op2)
+    return zf
+
+
+def expr_is_not_equal(op1, op2):
+    """
+    if op1 != op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    zf = _expr_compute_zf(op1, op2)
+    return ~zf
+
+
+def expr_is_unsigned_greater(op1, op2):
+    """
+    UNSIGNED cmp
+    if op1 > op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    cf = _expr_compute_cf(op1, op2)
+    zf = _expr_compute_zf(op1, op2)
+    return ~(cf | zf)
+
+
+def expr_is_unsigned_greater_or_equal(op1, op2):
+    """
+    Unsigned cmp
+    if op1 >= op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    cf = _expr_compute_cf(op1, op2)
+    return ~cf
+
+
+def expr_is_unsigned_lower(op1, op2):
+    """
+    Unsigned cmp
+    if op1 < op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    cf = _expr_compute_cf(op1, op2)
+    return cf
+
+
+def expr_is_unsigned_lower_or_equal(op1, op2):
+    """
+    Unsigned cmp
+    if op1 <= op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    cf = _expr_compute_cf(op1, op2)
+    zf = _expr_compute_zf(op1, op2)
+    return cf | zf
+
+
+def expr_is_signed_greater(op1, op2):
+    """
+    Signed cmp
+    if op1 > op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    nf = _expr_compute_nf(op1, op2)
+    of = _expr_compute_of(op1, op2)
+    zf = _expr_compute_zf(op1, op2)
+    return ~(zf | (nf ^ of))
+
+
+def expr_is_signed_greater_or_equal(op1, op2):
+    """
+    Signed cmp
+    if op1 > op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    nf = _expr_compute_nf(op1, op2)
+    of = _expr_compute_of(op1, op2)
+    return ~(nf ^ of)
+
+
+def expr_is_signed_lower(op1, op2):
+    """
+    Signed cmp
+    if op1 < op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    nf = _expr_compute_nf(op1, op2)
+    of = _expr_compute_of(op1, op2)
+    return nf ^ of
+
+
+def expr_is_signed_lower_or_equal(op1, op2):
+    """
+    Signed cmp
+    if op1 <= op2:
+       Return ExprInt(1, 1)
+    else:
+       Return ExprInt(0, 1)
+    """
+
+    nf = _expr_compute_nf(op1, op2)
+    of = _expr_compute_of(op1, op2)
+    zf = _expr_compute_zf(op1, op2)
+    return zf | (nf ^ of)
diff --git a/test/expression/expr_cmp.py b/test/expression/expr_cmp.py
new file mode 100644
index 00000000..b238151d
--- /dev/null
+++ b/test/expression/expr_cmp.py
@@ -0,0 +1,107 @@
+#
+# Expression comparison regression tests  #
+#
+from pdb import pm
+from miasm2.expression.expression import ExprInt, expr_is_unsigned_greater,\
+    expr_is_unsigned_greater_or_equal, expr_is_unsigned_lower,\
+    expr_is_unsigned_lower_or_equal, expr_is_signed_greater,\
+    expr_is_signed_greater_or_equal, expr_is_signed_lower, \
+    expr_is_signed_lower_or_equal, expr_is_equal, expr_is_not_equal
+from miasm2.expression.simplifications import expr_simp
+
+int_0 = ExprInt(0, 32)
+int_1 = ExprInt(1, 32)
+int_m1 = ExprInt(-1, 32)
+int_m2 = ExprInt(-2, 32)
+
+b0 = ExprInt(0, 1)
+b1 = ExprInt(1, 1)
+
+tests = [
+    # unsigned
+    (b1, expr_is_unsigned_greater, int_1, int_0),
+    (b1, expr_is_unsigned_lower, int_0, int_1),
+
+    (b0, expr_is_unsigned_greater, int_0, int_1),
+    (b0, expr_is_unsigned_lower, int_1, int_0),
+
+    (b1, expr_is_unsigned_greater_or_equal, int_1, int_0),
+    (b1, expr_is_unsigned_lower_or_equal, int_0, int_1),
+
+    (b0, expr_is_unsigned_greater_or_equal, int_0, int_1),
+    (b0, expr_is_unsigned_lower_or_equal, int_1, int_0),
+
+    (b1, expr_is_unsigned_greater_or_equal, int_1, int_1),
+    (b1, expr_is_unsigned_lower_or_equal, int_1, int_1),
+
+    (b1, expr_is_unsigned_greater, int_m1, int_0),
+    (b1, expr_is_unsigned_lower, int_0, int_m1),
+
+    (b0, expr_is_unsigned_greater, int_0, int_m1),
+    (b0, expr_is_unsigned_lower, int_m1, int_0),
+
+
+    # signed
+    (b1, expr_is_signed_greater, int_1, int_0),
+    (b1, expr_is_signed_lower, int_0, int_1),
+
+    (b0, expr_is_signed_greater, int_0, int_1),
+    (b0, expr_is_signed_lower, int_1, int_0),
+
+    (b1, expr_is_signed_greater_or_equal, int_1, int_0),
+    (b1, expr_is_signed_lower_or_equal, int_0, int_1),
+
+    (b0, expr_is_signed_greater_or_equal, int_0, int_1),
+    (b0, expr_is_signed_lower_or_equal, int_1, int_0),
+
+    (b1, expr_is_signed_greater_or_equal, int_1, int_1),
+    (b1, expr_is_signed_lower_or_equal, int_1, int_1),
+
+    (b0, expr_is_signed_greater, int_m1, int_0),
+    (b0, expr_is_signed_lower, int_0, int_m1),
+
+    (b1, expr_is_signed_greater, int_0, int_m1),
+    (b1, expr_is_signed_lower, int_m1, int_0),
+
+
+    # greater lesser, neg
+    (b1, expr_is_signed_greater, int_1, int_m1),
+    (b1, expr_is_signed_lower, int_m1, int_1),
+
+    (b0, expr_is_signed_greater, int_m1, int_1),
+    (b0, expr_is_signed_lower, int_1, int_m1),
+
+    (b1, expr_is_signed_greater_or_equal, int_1, int_m1),
+    (b1, expr_is_signed_lower_or_equal, int_m1, int_1),
+
+    (b0, expr_is_signed_greater_or_equal, int_m1, int_1),
+    (b0, expr_is_signed_lower_or_equal, int_1, int_m1),
+
+    (b1, expr_is_signed_greater_or_equal, int_m1, int_m1),
+    (b1, expr_is_signed_lower_or_equal, int_m1, int_m1),
+
+
+    (b1, expr_is_signed_greater, int_m1, int_m2),
+    (b1, expr_is_signed_lower, int_m2, int_m1),
+
+    (b0, expr_is_signed_greater, int_m2, int_m1),
+    (b0, expr_is_signed_lower, int_m1, int_m2),
+
+    (b1, expr_is_signed_greater_or_equal, int_m1, int_m2),
+    (b1, expr_is_signed_lower_or_equal, int_m2, int_m1),
+
+    (b0, expr_is_signed_greater_or_equal, int_m2, int_m1),
+    (b0, expr_is_signed_lower_or_equal, int_m1, int_m2),
+
+    # eq/neq
+    (b1, expr_is_equal, int_1, int_1),
+    (b1, expr_is_not_equal, int_0, int_1),
+
+    (b0, expr_is_equal, int_1, int_0),
+    (b0, expr_is_not_equal, int_0, int_0),
+
+
+]
+
+for result, func, arg1, arg2 in tests:
+    assert result == expr_simp(func(arg1, arg2))
diff --git a/test/test_all.py b/test/test_all.py
index 17193d9f..70ad62b8 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -245,6 +245,7 @@ for script in ["modint.py",
                "expression_helper.py",
                "expr_pickle.py",
                "parser.py",
+               "expr_cmp.py",
                ]:
     testset += RegressionTest([script], base_dir="expression")