about summary refs log tree commit diff stats
path: root/miasm2/arch/x86/sem.py
diff options
context:
space:
mode:
Diffstat (limited to 'miasm2/arch/x86/sem.py')
-rw-r--r--miasm2/arch/x86/sem.py281
1 files changed, 133 insertions, 148 deletions
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
index b622e930..0e83de8c 100644
--- a/miasm2/arch/x86/sem.py
+++ b/miasm2/arch/x86/sem.py
@@ -73,8 +73,8 @@ def update_flag_pf(a):
                                            a & m2_expr.ExprInt_from(a, 0xFF)))]
 
 
-def update_flag_af(expr):
-    return [m2_expr.ExprAff(af, expr[4:5])]
+def update_flag_af(op1, op2, res):
+    return [m2_expr.ExprAff(af, (op1 ^ op2 ^ res)[4:5])]
 
 
 def update_flag_znp(a):
@@ -286,7 +286,7 @@ def add(ir, instr, a, b):
     e = []
     c = a + b
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     e += update_flag_add(a, b, c)
     e.append(m2_expr.ExprAff(a, c))
     return e, []
@@ -296,7 +296,7 @@ def xadd(ir, instr, a, b):
     e = []
     c = a + b
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     e += update_flag_add(b, a, c)
     e.append(m2_expr.ExprAff(b, a))
     e.append(m2_expr.ExprAff(a, c))
@@ -309,7 +309,7 @@ def adc(ir, instr, a, b):
                                        1, a.size),
                               (cf, 0, 1)]))
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     e += update_flag_add(a, b, c)
     e.append(m2_expr.ExprAff(a, c))
     return e, []
@@ -319,7 +319,7 @@ def sub(ir, instr, a, b):
     e = []
     c = a - b
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     e += update_flag_sub(a, b, c)
     e.append(m2_expr.ExprAff(a, c))
     return e, []
@@ -333,7 +333,7 @@ def sbb(ir, instr, a, b):
                                        1, a.size),
                               (cf, 0, 1)]))
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     e += update_flag_sub(a, b, c)
     e.append(m2_expr.ExprAff(a, c))
     return e, []
@@ -346,7 +346,7 @@ def neg(ir, instr, b):
     c = a - b
     e += update_flag_arith(c)
     e += update_flag_sub(a, b, c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     e.append(m2_expr.ExprAff(b, c))
     return e, []
 
@@ -363,7 +363,7 @@ def l_cmp(ir, instr, a, b):
     c = a - b
     e += update_flag_arith(c)
     e += update_flag_sub(a, b, c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
     return e, []
 
 
@@ -415,125 +415,157 @@ def get_shift(a, b):
     shift = expr_simp(shift)
     return shift
 
-
-def l_rol(ir, instr, a, b):
-    e = []
-    shifter = get_shift(a, b)
-    c = m2_expr.ExprOp('<<<', a, shifter)
-
-    new_cf = c[:1]
-    e.append(m2_expr.ExprAff(cf, new_cf))
-    # hack (only valid if b=1)
-    e.append(m2_expr.ExprAff(of, c.msb() ^ new_cf))
-    e.append(m2_expr.ExprAff(a, c))
-    return e, []
-
-
-def l_ror(ir, instr, a, b):
-    e = []
-    shifter = get_shift(a, b)
-    c = m2_expr.ExprOp('>>>', a, shifter)
-
-    e.append(m2_expr.ExprAff(cf, c.msb()))
-    # hack (only valid if b=1): when count == 1: a = msb-1(dest)
-    e.append(m2_expr.ExprAff(of, (c ^ a).msb()))
-    e.append(m2_expr.ExprAff(a, c))
-    return e, []
-
-
-def rcl(ir, instr, a, b):
-    e = []
-    shifter = get_shift(a, b)
-    c = m2_expr.ExprOp('<<<c_rez', a, shifter, cf.zeroExtend(a.size))
-    new_cf = m2_expr.ExprOp('<<<c_cf', a, shifter, cf.zeroExtend(a.size))[:1]
-
-    e.append(m2_expr.ExprAff(cf, new_cf))
-    # hack (only valid if b=1)
-    e.append(m2_expr.ExprAff(of, c.msb() ^ new_cf))
-    e.append(m2_expr.ExprAff(a, c))
-    return e, []
-
-
-def rcr(ir, instr, a, b):
-    e = []
-    shifter = get_shift(a, b)
-    c = m2_expr.ExprOp('>>>c_rez', a, shifter, cf.zeroExtend(a.size))
-    new_cf = m2_expr.ExprOp('>>>c_cf', a, shifter, cf.zeroExtend(a.size))[:1]
-
-    e.append(m2_expr.ExprAff(cf, new_cf))
-    # hack (only valid if b=1)
-    e.append(m2_expr.ExprAff(of, (a ^ c).msb()))
-    e.append(m2_expr.ExprAff(a, c))
-
-    return e, []
-
-
-def sar(ir, instr, a, b):
-
+def _rotate_tpl(ir, instr, a, b, op, left=False, include_cf=False):
+    """Template to generate a rotater with operation @op
+    A temporary basic block is generated to handle 0-rotate
+    @op: operation to execute
+    @left (optional): indicates a left rotate if set, default is False
+    @include_cf (optional): if set, add cf to @op inputs, default is False
+    """
+    # Compute results
     shifter = get_shift(a, b)
-    c = m2_expr.ExprOp('a>>', a, shifter)
-
-    lbl_do = m2_expr.ExprId(ir.gen_label(), instr.mode)
-    lbl_skip = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
-
-    new_cf = m2_expr.ExprOp('a>>', a,(shifter - m2_expr.ExprInt_from(a, 1)))[:1]
-
+    extended_args = (cf.zeroExtend(a.size),) if include_cf else ()
+    res = m2_expr.ExprOp(op, a, shifter, *extended_args)
+
+    # CF is computed with 1-less round than `res`
+    new_cf = m2_expr.ExprOp(op, a,
+                            shifter - m2_expr.ExprInt(1, size=shifter.size),
+                            *extended_args)
+    new_cf = new_cf.msb() if left else new_cf[:1]
+
+    # OF is defined only for @b == 1
+    new_of = m2_expr.ExprCond(b - m2_expr.ExprInt(1, size=b.size),
+                              m2_expr.ExprInt(0, size=of.size),
+                              res.msb() ^ new_cf if left else (a ^ res).msb())
+    # Build basic blocks
     e_do = [
         m2_expr.ExprAff(cf, new_cf),
-        m2_expr.ExprAff(of, m2_expr.ExprInt_from(of, 0)),
-        m2_expr.ExprAff(a, c),
+        m2_expr.ExprAff(of, new_of),
+        m2_expr.ExprAff(a, res),
     ]
 
-    e_do += update_flag_znp(c)
-
-    # dont generate conditional shifter on constant
+    # Don't generate conditional shifter on constant
     if isinstance(shifter, m2_expr.ExprInt):
         if int(shifter.arg) != 0:
             return e_do, []
         else:
             return [], []
 
-    e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
-
     e = []
+    lbl_do = m2_expr.ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
+    e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
     e.append(m2_expr.ExprAff(ir.IRDst, m2_expr.ExprCond(shifter, lbl_do,
                                                         lbl_skip)))
     return e, [irbloc(lbl_do.name, [e_do])]
 
 
-def shr(ir, instr, a, b):
+def l_rol(ir, instr, a, b):
+    return _rotate_tpl(ir, instr, a, b, '<<<', left=True)
 
-    shifter = get_shift(a, b)
-    c = m2_expr.ExprOp('>>', a, shifter)
 
-    lbl_do = m2_expr.ExprId(ir.gen_label(), instr.mode)
-    lbl_skip = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
+def l_ror(ir, instr, a, b):
+    return _rotate_tpl(ir, instr, a, b, '>>>')
 
-    new_cf = m2_expr.ExprOp('>>', a, (shifter - m2_expr.ExprInt_from(a, 1)))[:1]
 
+def rcl(ir, instr, a, b):
+    return _rotate_tpl(ir, instr, a, b, '<<<c_rez', left=True, include_cf=True)
+
+
+def rcr(ir, instr, a, b):
+    return _rotate_tpl(ir, instr, a, b, '>>>c_rez', include_cf=True)
+
+
+def _shift_tpl(op, ir, instr, a, b, c=None, op_inv=None, left=False,
+               custom_of=None):
+    """Template to generate a shifter with operation @op
+    A temporary basic block is generated to handle 0-shift
+    @op: operation to execute
+    @c (optional): if set, instruction has a bit provider
+    @op_inv (optional): opposite operation of @op. Must be provided if @c
+    @left (optional): indicates a left shift if set, default is False
+    @custom_of (optional): if set, override the computed value of OF
+    """
+    if c is not None:
+        shifter = get_shift(a, c)
+    else:
+        shifter = get_shift(a, b)
+
+    res = m2_expr.ExprOp(op, a, shifter)
+    cf_from_dst = m2_expr.ExprOp(op, a,
+                                 (shifter - m2_expr.ExprInt_from(a, 1)))
+    cf_from_dst = cf_from_dst.msb() if left else cf_from_dst[:1]
+
+    new_cf = cf_from_dst
+    i1 = m2_expr.ExprInt(1, size=a.size)
+    if c is not None:
+        # There is a source for new bits
+        isize = m2_expr.ExprInt(a.size, size=a.size)
+        mask = m2_expr.ExprOp(op_inv, i1, (isize - shifter)) - i1
+
+        # An overflow can occured, emulate the 'undefined behavior'
+        # Overflow behavior if (shift / size % 2)
+        base_cond_overflow = c if left else (c - m2_expr.ExprInt(1, size=c.size))
+        cond_overflow = base_cond_overflow & m2_expr.ExprInt(a.size, c.size)
+        if left:
+            # Overflow occurs one round before right
+            mask = m2_expr.ExprCond(cond_overflow, mask, ~mask)
+        else:
+            mask = m2_expr.ExprCond(cond_overflow, ~mask, mask)
+
+        # Build res with dst and src
+        res = ((m2_expr.ExprOp(op, a, shifter) & mask) |
+               (m2_expr.ExprOp(op_inv, b, (isize - shifter)) & ~mask))
+
+        # Overflow case: cf come from src (bit number shifter % size)
+        cf_from_src = m2_expr.ExprOp(op, b,
+                                     (c.zeroExtend(b.size) &
+                                      m2_expr.ExprInt(a.size - 1, b.size)) - i1)
+        cf_from_src = cf_from_src.msb() if left else cf_from_src[:1]
+        new_cf = m2_expr.ExprCond(cond_overflow, cf_from_src, cf_from_dst)
+
+    # Overflow flag, only occured when shifter is equal to 1
+    if custom_of is None:
+        value_of = a.msb() ^ a[-2:-1] if left else b[:1] ^ a.msb()
+    else:
+        value_of = custom_of
+
+    # Build basic blocks
     e_do = [
         m2_expr.ExprAff(cf, new_cf),
-        m2_expr.ExprAff(of, m2_expr.ExprInt_from(of, 0)),
-        m2_expr.ExprAff(a, c),
+        m2_expr.ExprAff(of, m2_expr.ExprCond(shifter - i1,
+                                             m2_expr.ExprInt_from(of, 0),
+                                             value_of)),
+        m2_expr.ExprAff(a, res),
     ]
+    e_do += update_flag_znp(res)
 
-    e_do += update_flag_znp(c)
-
-    # dont generate conditional shifter on constant
+    # Don't generate conditional shifter on constant
     if isinstance(shifter, m2_expr.ExprInt):
         if int(shifter.arg) != 0:
             return e_do, []
         else:
             return [], []
 
-    e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
-
     e = []
+    lbl_do = m2_expr.ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
+    e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
     e.append(m2_expr.ExprAff(ir.IRDst, m2_expr.ExprCond(shifter, lbl_do,
                                                         lbl_skip)))
     return e, [irbloc(lbl_do.name, [e_do])]
 
 
+def sar(ir, instr, a, b):
+    # Fixup OF, always cleared if b != 0
+    i0 = m2_expr.ExprInt(0, size=of.size)
+    return _shift_tpl("a>>", ir, instr, a, b, custom_of=i0)
+
+
+def shr(ir, instr, a, b):
+    return _shift_tpl(">>", ir, instr, a, b, custom_of=a.msb())
+
+
 def shrd_cl(ir, instr, a, b):
     e = []
     opmode, admode = s, instr.v_admode()
@@ -553,20 +585,7 @@ def shrd_cl(ir, instr, a, b):
 
 
 def shrd(ir, instr, a, b, c):
-    e = []
-    shifter = get_shift(a, c)
-
-    d = (a >> shifter) | (b << (m2_expr.ExprInt_from(a, a.size) - shifter))
-    new_cf = (a >> (shifter - m2_expr.ExprInt_from(a, 1)))[:1]
-    e.append(m2_expr.ExprAff(cf, m2_expr.ExprCond(shifter,
-                                  new_cf,
-                                  cf)
-                     )
-             )
-    e.append(m2_expr.ExprAff(of, a.msb()))
-    e += update_flag_znp(d)
-    e.append(m2_expr.ExprAff(a, d))
-    return e, []
+    return _shift_tpl(">>>", ir, instr, a, b, c, "<<<")
 
 
 def sal(ir, instr, a, b):
@@ -586,19 +605,7 @@ def sal(ir, instr, a, b):
 
 
 def shl(ir, instr, a, b):
-    e = []
-    shifter = get_shift(a, b)
-    c = a << shifter
-    new_cf = (a >> (m2_expr.ExprInt_from(a, a.size) - shifter))[:1]
-    e.append(m2_expr.ExprAff(cf, m2_expr.ExprCond(shifter,
-                                  new_cf,
-                                  cf)
-                     )
-             )
-    e += update_flag_znp(c)
-    e.append(m2_expr.ExprAff(of, c.msb() ^ new_cf))
-    e.append(m2_expr.ExprAff(a, c))
-    return e, []
+    return _shift_tpl("<<", ir, instr, a, b, left=True)
 
 
 def shld_cl(ir, instr, a, b):
@@ -606,26 +613,7 @@ def shld_cl(ir, instr, a, b):
 
 
 def shld(ir, instr, a, b, c):
-    e = []
-    shifter = c.zeroExtend(a.size) & m2_expr.ExprInt_from(a, 0x1f)
-    c = m2_expr.ExprOp('|',
-               a << shifter,
-               b >> (m2_expr.ExprInt_from(a, a.size) - shifter)
-               )
-
-    new_cf = (a >> (m2_expr.ExprInt_from(a, a.size) - shifter))[:1]
-    e.append(m2_expr.ExprAff(cf, m2_expr.ExprCond(shifter,
-                                  new_cf,
-                                  cf)
-                     )
-             )
-    # XXX todo: don't update flag if shifter is 0
-    e += update_flag_znp(c)
-    e.append(m2_expr.ExprAff(of, c.msb() ^ new_cf))
-    e.append(m2_expr.ExprAff(a, m2_expr.ExprCond(shifter,
-                                 c,
-                                 a)))
-    return e, []
+    return _shift_tpl("<<<", ir, instr, a, b, c, ">>>", left=True)
 
 
 # XXX todo ###
@@ -671,7 +659,7 @@ def inc(ir, instr, a):
     b = m2_expr.ExprInt_from(a, 1)
     c = a + b
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, c)
 
     e.append(update_flag_add_of(a, b, c))
     e.append(m2_expr.ExprAff(a, c))
@@ -682,7 +670,7 @@ def dec(ir, instr, a):
     b = m2_expr.ExprInt_from(a, -1)
     c = a + b
     e += update_flag_arith(c)
-    e += update_flag_af(c)
+    e += update_flag_af(a, b, ~c)
 
     e.append(update_flag_add_of(a, b, c))
     e.append(m2_expr.ExprAff(a, c))
@@ -1357,8 +1345,7 @@ def jno(ir, instr, dst):
 def loop(ir, instr, dst):
     e = []
     meip = mRIP[instr.mode]
-    s = instr.v_opmode()
-    opmode, admode = s, instr.v_admode()
+    admode = instr.v_admode()
     myecx = mRCX[instr.mode][:admode]
 
     n = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
@@ -1375,13 +1362,12 @@ def loop(ir, instr, dst):
 def loopne(ir, instr, dst):
     e = []
     meip = mRIP[instr.mode]
-    s = instr.v_opmode()
-    opmode, admode = s, instr.v_admode()
+    admode = instr.v_admode()
     myecx = mRCX[instr.mode][:admode]
 
     n = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
 
-    c = m2_expr.ExprCond(mRCX[instr.mode][:s] - m2_expr.ExprInt(1, s),
+    c = m2_expr.ExprCond(myecx - m2_expr.ExprInt(1, size=myecx.size),
                  m2_expr.ExprInt1(1),
                  m2_expr.ExprInt1(0))
     c &= zf ^ m2_expr.ExprInt1(1)
@@ -1398,12 +1384,11 @@ def loopne(ir, instr, dst):
 def loope(ir, instr, dst):
     e = []
     meip = mRIP[instr.mode]
-    s = instr.v_opmode()
-    opmode, admode = s, instr.v_admode()
+    admode = instr.v_admode()
     myecx = mRCX[instr.mode][:admode]
 
     n = m2_expr.ExprId(ir.get_next_label(instr), instr.mode)
-    c = m2_expr.ExprCond(mRCX[instr.mode][:s] - m2_expr.ExprInt(1, s),
+    c = m2_expr.ExprCond(myecx - m2_expr.ExprInt(1, size=myecx.size),
                  m2_expr.ExprInt1(1),
                  m2_expr.ExprInt1(0))
     c &= zf