about summary refs log tree commit diff stats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--miasm/arch/arm/arch.py4
-rw-r--r--miasm/arch/arm/sem.py283
-rw-r--r--test/arch/arm/arch.py7
-rwxr-xr-xtest/arch/arm/sem.py55
4 files changed, 270 insertions, 79 deletions
diff --git a/miasm/arch/arm/arch.py b/miasm/arch/arm/arch.py
index 5ccf5eca..91c22bd5 100644
--- a/miasm/arch/arm/arch.py
+++ b/miasm/arch/arm/arch.py
@@ -1148,8 +1148,12 @@ class arm_op2(arm_arg):
             shift_op = ExprInt(amount, 32)
         a = regs_expr[rm]
         if shift_op == ExprInt(0, 32):
+            #rrx
             if shift_type == 3:
                 self.expr = ExprOp(allshifts[4], a)
+            #asr, lsr
+            elif shift_type == 1 or shift_type == 2:
+                self.expr = ExprOp(allshifts[shift_type], a, ExprInt(32, 32))
             else:
                 self.expr = a
         else:
diff --git a/miasm/arch/arm/sem.py b/miasm/arch/arm/sem.py
index e507a045..a138ef91 100644
--- a/miasm/arch/arm/sem.py
+++ b/miasm/arch/arm/sem.py
@@ -2,6 +2,7 @@ from builtins import range
 from future.utils import viewitems, viewvalues
 
 from miasm.expression.expression import *
+from miasm.expression.simplifications import expr_simp
 from miasm.ir.ir import Lifter, IRBlock, AssignBlock
 from miasm.arch.arm.arch import mn_arm, mn_armt
 from miasm.arch.arm.regs import *
@@ -253,6 +254,15 @@ def update_flag_zn(a):
     return e
 
 
+# Instructions which use shifter's carry flag: ANDS, BICS, EORS, MOVS/RRX, MVNS, ORNS (TODO), ORRS, TEQ, TST
+def compute_rrx_carry(operation):
+    """
+    Returns a tuple (result, carry) corresponding to the RRX computation
+    @operation: The ExprOp operation
+    """
+    new_cf = operation.args[0][:1]
+    res = ExprCompose(operation.args[0][1:], cf)
+    return res, new_cf
 
 # XXX TODO: set cf if ROT imm in argument
 
@@ -272,12 +282,12 @@ def update_flag_add_of(op1, op2):
 
 
 def update_flag_sub_cf(op1, op2):
-    "Compote CF in @op1 - @op2"
+    "Compute CF in @op1 - @op2"
     return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))]
 
 
 def update_flag_sub_of(op1, op2):
-    "Compote OF in @op1 - @op2"
+    "Compute OF in @op1 - @op2"
     return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))]
 
 
@@ -381,6 +391,9 @@ def update_flag_arith_subwc_co(arg1, arg2, arg3):
     e += update_flag_subwc_of(arg1, arg2, arg3)
     return e
 
+# Utility function for flag computation when it depends on the mode
+def isThumb(lifter):
+    return isinstance(lifter, (Lifter_Armtl, Lifter_Armtb))
 
 
 def get_dst(a):
@@ -395,6 +408,8 @@ def adc(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = b, c
     r = b + c + cf.zeroExtend(32)
     if instr.name == 'ADCS' and a != PC:
@@ -411,6 +426,8 @@ def add(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = b, c
     r = b + c
     if instr.name == 'ADDS' and a != PC:
@@ -424,11 +441,18 @@ def add(ir, instr, a, b, c=None):
 
 
 def l_and(ir, instr, a, b, c=None):
-    e = []
+    setflags = (instr.name == 'ANDS') and a != PC
     if c is None:
         b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
     r = b & c
-    if instr.name == 'ANDS' and a != PC:
+    if setflags:
         e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', b, c))]
         e += update_flag_nf(r)
 
@@ -436,13 +460,14 @@ def l_and(ir, instr, a, b, c=None):
     dst = get_dst(a)
     if dst is not None:
         e.append(ExprAssign(ir.IRDst, r))
-    return e, []
-
+    return e, extra_ir
 
 def sub(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = b - c
     e.append(ExprAssign(a, r))
     dst = get_dst(a)
@@ -455,6 +480,8 @@ def subs(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = b, c
     r = b - c
     e += update_flag_arith_sub_zn(arg1, arg2)
@@ -470,6 +497,8 @@ def eor(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = b ^ c
     e.append(ExprAssign(a, r))
     dst = get_dst(a)
@@ -479,9 +508,16 @@ def eor(ir, instr, a, b, c=None):
 
 
 def eors(ir, instr, a, b, c=None):
-    e = []
+    setflags = a != PC
     if c is None:
         b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
     arg1, arg2 = b, c
     r = arg1 ^ arg2
 
@@ -492,13 +528,15 @@ def eors(ir, instr, a, b, c=None):
     dst = get_dst(a)
     if dst is not None:
         e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    return e, extra_ir
 
 
 def rsb(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = c, b
     r = arg1 - arg2
     e.append(ExprAssign(a, r))
@@ -512,6 +550,8 @@ def rsbs(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = c, b
     r = arg1 - arg2
     e += update_flag_arith_sub_zn(arg1, arg2)
@@ -527,6 +567,8 @@ def sbc(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = b, c
     r = arg1 - (arg2 + (~cf).zeroExtend(32))
     e.append(ExprAssign(a, r))
@@ -540,6 +582,8 @@ def sbcs(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = b, c
     r = arg1 - (arg2 + (~cf).zeroExtend(32))
 
@@ -557,6 +601,8 @@ def rsc(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = c, b
     r = arg1 - (arg2 + (~cf).zeroExtend(32))
     e.append(ExprAssign(a, r))
@@ -570,6 +616,8 @@ def rscs(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = c, b
     r = arg1 - (arg2 + (~cf).zeroExtend(32))
 
@@ -585,18 +633,32 @@ def rscs(ir, instr, a, b, c=None):
 
 
 def tst(ir, instr, a, b):
-    e = []
+    setflags = a != PC
+    if b.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags)
+        # get back the result
+        b = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
     arg1, arg2 = a, b
     r = arg1 & arg2
 
     e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
     e += update_flag_nf(r)
 
-    return e, []
+    return e, extra_ir
 
 
 def teq(ir, instr, a, b, c=None):
-    e = []
+    setflags = a != PC
+    if b.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags)
+        # get back the result
+        b = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
     if c is None:
         b, c = a, b
     arg1, arg2 = b, c
@@ -605,7 +667,7 @@ def teq(ir, instr, a, b, c=None):
     e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))]
     e += update_flag_nf(r)
 
-    return e, []
+    return e, extra_ir
 
 
 def l_cmp(ir, instr, a, b, c=None):
@@ -622,6 +684,8 @@ def cmn(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     arg1, arg2 = b, c
     e += update_flag_arith_add_zn(arg1, arg2)
     e += update_flag_arith_add_co(arg1, arg2)
@@ -632,6 +696,8 @@ def orr(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = b | c
     e.append(ExprAssign(a, r))
     dst = get_dst(a)
@@ -644,6 +710,8 @@ def orn(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = ~(b | c)
     e.append(ExprAssign(a, r))
     dst = get_dst(a)
@@ -653,9 +721,16 @@ def orn(ir, instr, a, b, c=None):
 
 
 def orrs(ir, instr, a, b, c=None):
-    e = []
+    setflags = a != PC
     if c is None:
         b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
     arg1, arg2 = b, c
     r = arg1 | arg2
 
@@ -666,10 +741,13 @@ def orrs(ir, instr, a, b, c=None):
     dst = get_dst(a)
     if dst is not None:
         e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    return e, extra_ir
 
 
 def mov(ir, instr, a, b):
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags=False)
+    # TODO handle cf
     e = [ExprAssign(a, b)]
     dst = get_dst(a)
     if dst is not None:
@@ -686,10 +764,78 @@ def movt(ir, instr, a, b):
     return e, []
 
 
+def _shift_rotate_tpl(ir, instr, dst, shift_operation, setflags=False, is_not=False, onlyCarry=False):
+    """
+    Template to generate a shift/rotate
+    A temporary basic block is generated to handle 0-shift
+    @dst: destination
+    @shift_operation: the shift/rotate operation (ExprOp)
+    @setflags: (optional) if set, flags are updated (ZNC)
+    @onlyCarry: (optional) if set, Z and N flags won't be updated except if setflags is set.
+    @is_not: (optional) if set, behaves as MVN/MVNS
+    """
+    op = shift_operation.op
+    # Compute carry (+ result for rrx)
+    if op == 'rrx':
+        res, new_cf = compute_rrx_carry(shift_operation)
+        shifter = ExprInt(1, 8)
+    elif op in ['<<', '>>', 'a>>']:
+        shifter = shift_operation.args[1]
+        if setflags or onlyCarry:
+            new_cf = ExprOp(op, shift_operation.args[0], shifter - ExprInt(1, size=shifter.size))
+            left = op[-1] == '<'
+            new_cf = new_cf.msb() if left else new_cf[:1]
+        res = shift_operation
+    elif op == '>>>':
+        shifter = shift_operation.args[1]
+        if setflags or onlyCarry:
+            new_cf = shift_operation.msb()
+        res = shift_operation
+    else:
+        raise NotImplementedError(f"Unknown shift / rotate operation : {op}")
+
+    # NOT the result and use it for ZN flags computations
+    if is_not:
+        res ^= ExprInt(-1, res.size)
+    # Build basic blocks
+    e_do = []
+    e = [ExprAssign(dst, res)]
+    if setflags:
+        e += update_flag_zn(res)
+    if setflags or onlyCarry:
+        e_do += [ExprAssign(cf, expr_simp(new_cf))]
+    # Don't generate conditional shifter on constant
+    if shifter.is_int():
+        if shifter.is_int(0):
+            # assignement + flags if setflags except cf
+            return (e, [])
+        else:
+            # assignement + flags if setflags
+            return (e + e_do, [])
+
+    loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
+    loc_skip = ir.get_next_loc_key(instr)
+    loc_skip_expr = ExprLoc(loc_skip, ir.IRDst.size)
+    isPC = get_dst(dst)
+    if isPC is not None:
+        # Not really a Loc in this case
+        loc_skip_expr = res
+    e_do.append(ExprAssign(ir.IRDst, loc_skip_expr))
+    e.append(ExprAssign(
+        ir.IRDst, ExprCond(shifter, loc_do_expr, loc_skip_expr)))
+    return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])])
+
+
+
 def movs(ir, instr, a, b):
     e = []
+    # handle shift / rotate
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags=a != PC)
+
+
     e.append(ExprAssign(a, b))
-    # XXX TODO check
+    # TODO handle cf
     e += [ExprAssign(zf, ExprOp('FLAG_EQ', b))]
     e += update_flag_nf(b)
 
@@ -700,7 +846,10 @@ def movs(ir, instr, a, b):
 
 
 def mvn(ir, instr, a, b):
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags=False, is_not=True)
     r = b ^ ExprInt(-1, 32)
+    # TODO handle cf
     e = [ExprAssign(a, r)]
     dst = get_dst(a)
     if dst is not None:
@@ -709,10 +858,12 @@ def mvn(ir, instr, a, b):
 
 
 def mvns(ir, instr, a, b):
+    if b.is_op():
+        return _shift_rotate_tpl(ir, instr, a, b, setflags= a != PC, is_not=True)
     e = []
     r = b ^ ExprInt(-1, 32)
     e.append(ExprAssign(a, r))
-    # XXX TODO check
+    # TODO handle cf
     e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
     e += update_flag_nf(r)
 
@@ -765,6 +916,8 @@ def bic(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = b & (c ^ ExprInt(-1, 32))
     e.append(ExprAssign(a, r))
     dst = get_dst(a)
@@ -774,9 +927,16 @@ def bic(ir, instr, a, b, c=None):
 
 
 def bics(ir, instr, a, b, c=None):
-    e = []
+    setflags = a != PC
     if c is None:
         b, c = a, b
+    if c.is_op():
+        e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
+        # get back the result
+        c = e.pop(0).src
+    else:
+        e = []
+        extra_ir = []
     tmp1, tmp2 = b, ~c
     r = tmp1 & tmp2
 
@@ -787,13 +947,15 @@ def bics(ir, instr, a, b, c=None):
     dst = get_dst(a)
     if dst is not None:
         e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    return e, extra_ir
 
 
 def sdiv(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
 
     loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
     loc_except = ExprId(ir.loc_db.add_location(), ir.IRDst.size)
@@ -825,6 +987,8 @@ def udiv(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
 
 
 
@@ -888,6 +1052,8 @@ def mul(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = b * c
     e.append(ExprAssign(a, r))
     dst = get_dst(a)
@@ -900,6 +1066,8 @@ def muls(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = b * c
     e += update_flag_zn(r)
     e.append(ExprAssign(a, r))
@@ -1169,100 +1337,65 @@ def und(ir, instr, a, b):
     e = []
     return e, []
 
-# TODO XXX implement correct CF for shifters
 def lsr(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
-    r = b >> c
-    e.append(ExprAssign(a, r))
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b >> c, setflags=False)
 
 
 def lsrs(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
-    r = b >> c
-    e.append(ExprAssign(a, r))
-
-    e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
-    e += update_flag_nf(r)
-
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b >> c, setflags= a != PC)
 
 def asr(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = ExprOp("a>>", b, c)
-    e.append(ExprAssign(a, r))
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    return _shift_rotate_tpl(ir, instr, a, r, setflags=False)
 
 def asrs(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
     r = ExprOp("a>>", b, c)
-    e.append(ExprAssign(a, r))
-
-    e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
-    e += update_flag_nf(r)
-
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC)
 
 def lsl(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
-    r = b << c
-    e.append(ExprAssign(a, r))
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b << c, setflags=False)
+
 
 
 def lsls(ir, instr, a, b, c=None):
     e = []
     if c is None:
         b, c = a, b
-    r = b << c
-    e.append(ExprAssign(a, r))
-
-    e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
-    e += update_flag_nf(r)
-
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
+    if c.is_op('rrx'):
+        c, _ = compute_rrx_carry(c)
+    return _shift_rotate_tpl(ir, instr, a, b << c, setflags= a != PC)
 
 
 def rors(ir, instr, a, b):
     e = []
     r = ExprOp(">>>", a, b)
-    e.append(ExprAssign(a, r))
-
-    e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
-    e += update_flag_nf(r)
+    return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC)
 
-    dst = get_dst(a)
-    if dst is not None:
-        e.append(ExprAssign(ir.IRDst, r))
-    return e, []
 
 
 def push(ir, instr, a):
@@ -1962,9 +2095,7 @@ class Lifter_Arml(Lifter):
         args = instr.args
         # ir = get_mnemo_expr(self, self.name.lower(), *args)
         if len(args) and isinstance(args[-1], ExprOp):
-            if args[-1].op == 'rrx':
-                args[-1] = ExprCompose(args[-1].args[0][1:], cf)
-            elif (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and
+            if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and
                   isinstance(args[-1].args[-1], ExprId)):
                 args[-1] = ExprOp(args[-1].op,
                                   args[-1].args[0],
diff --git a/test/arch/arm/arch.py b/test/arch/arm/arch.py
index 42e80772..a3f3a974 100644
--- a/test/arch/arm/arch.py
+++ b/test/arch/arm/arch.py
@@ -241,7 +241,12 @@ reg_tests_arm = [
      '110f111e'),
     ('XXXXXXXX    MCRCC      p15, 0x0, R8, c2, c0, 0x1',
      '308f023e'),
-
+    ('XXXXXXXX    MOV        R4, R4 ASR 0x20',
+     '4440a0e1'),
+    ('XXXXXXXX    MOV        R2, R5 LSR 0x20',
+     '2520a0e1'),
+    ('XXXXXXXX    MOVS       R2, R5 LSR 0x20',
+     '2520b0e1'),
 
 ]
 ts = time.time()
diff --git a/test/arch/arm/sem.py b/test/arch/arm/sem.py
index a5b6d5eb..343bc063 100755
--- a/test/arch/arm/sem.py
+++ b/test/arch/arm/sem.py
@@ -81,7 +81,7 @@ class TestARMSemantic(unittest.TestCase):
         self.assertEqual(
             compute('MOV R4, R4 LSR 31', {R4: 0xDEADBEEF, }), {R4: 0x00000001, })
         self.assertEqual(
-            compute('MOV R4, R4 LSR 32', {R4: 0xDEADBEEF, }), {R4: 0xDEADBEEF, })
+            compute('MOV R4, R4 LSR 32', {R4: 0xDEADBEEF, }), {R4: 0x0, })
         self.assertRaises(ValueError, compute, 'MOV R4, R4 LSR 33')
         self.assertEqual(
             compute('MOV R4, R4 LSR R5', {R4: 0xDEADBEEF, R5: 0xBADBAD01, }), {R4: 0x6F56DF77, R5: 0xBADBAD01, })
@@ -93,7 +93,7 @@ class TestARMSemantic(unittest.TestCase):
         self.assertEqual(
             compute('MOV R4, R4 ASR 31', {R4: 0xDEADBEEF, }), {R4: 0xFFFFFFFF, })
         self.assertEqual(
-            compute('MOV R4, R4 ASR 32', {R4: 0xDEADBEEF, }), {R4: 0xDEADBEEF, })
+            compute('MOV R4, R4 ASR 32', {R4: 0xDEADBEEF, }), {R4: 0xFFFFFFFF, })
         self.assertRaises(ValueError, compute, 'MOV R4, R4 ASR 33')
         self.assertEqual(
             compute('MOV R4, R4 ASR R5', {R4: 0xDEADBEEF, R5: 0xBADBAD01, }), {R4: 0xEF56DF77, R5: 0xBADBAD01, })
@@ -111,6 +111,57 @@ class TestARMSemantic(unittest.TestCase):
                          cf: 0, R4: 0x6F56DF77, })
         self.assertEqual(compute('MOV R4, R4 RRX   ', {cf: 1, R4: 0xDEADBEEF, }), {
                          cf: 1, R4: 0xEF56DF77, })
+        # S
+        self.assertEqual(
+            compute('MOVS R4, R4       ', {R4: 0xDEADBEEF, }), {R4: 0xDEADBEEF, nf: 1, zf: 0,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 LSL  0')
+        self.assertEqual(
+            compute('MOVS R4, R4 LSL  1', {R4: 0xDEADBEEF, }), {R4: 0xBD5B7DDE, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 LSL 16', {R4: 0xDEADBEEF, }), {R4: 0xBEEF0000, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 LSL 31', {R4: 0xDEADBEEF, }), {R4: 0x80000000, nf: 1, zf: 0, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 LSL 32')
+        self.assertEqual(
+            compute('MOVS R4, R4 LSL R5', {R4: 0xDEADBEEF, R5: 0xBADBAD01, }), {R4: 0xBD5B7DDE, R5: 0xBADBAD01, nf: 1, zf: 0, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 LSR  0')
+        self.assertEqual(
+            compute('MOVS R4, R4 LSR  1', {R4: 0xDEADBEEF, }), {R4: 0x6F56DF77, nf: 0, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 LSR 16', {R4: 0xDEADBEEF, }), {R4: 0x0000DEAD, nf: 0, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 LSR 31', {R4: 0xDEADBEEF, }), {R4: 0x00000001, nf: 0, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 LSR 32', {R4: 0xDEADBEEF, }), {R4: 0x0, nf: 0, zf: 1, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 LSR 33')
+        self.assertEqual(
+            compute('MOVS R4, R4 LSR R5', {R4: 0xDEADBEEF, R5: 0xBADBAD01, }), {R4: 0x6F56DF77, R5: 0xBADBAD01, nf: 0, zf: 0, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 ASR  0')
+        self.assertEqual(
+            compute('MOVS R4, R4 ASR  1', {R4: 0xDEADBEEF, }), {R4: 0xEF56DF77, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 ASR 16', {R4: 0xDEADBEEF, }), {R4: 0xFFFFDEAD, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 ASR 31', {R4: 0xDEADBEEF, }), {R4: 0xFFFFFFFF, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 ASR 32', {R4: 0xDEADBEEF, }), {R4: 0xFFFFFFFF, nf: 1, zf: 0, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 ASR 33')
+        self.assertEqual(
+            compute('MOVS R4, R4 ASR R5', {R4: 0xDEADBEEF, R5: 0xBADBAD01, }), {R4: 0xEF56DF77, R5: 0xBADBAD01, nf: 1, zf: 0, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 ROR  0')
+        self.assertEqual(
+            compute('MOVS R4, R4 ROR  1', {R4: 0xDEADBEEF, }), {R4: 0xEF56DF77, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 ROR 16', {R4: 0xDEADBEEF, }), {R4: 0xBEEFDEAD, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(
+            compute('MOVS R4, R4 ROR 31', {R4: 0xDEADBEEF, }), {R4: 0xBD5B7DDF, nf: 1, zf: 0, cf: 1,})
+        self.assertRaises(ValueError, compute, 'MOVS R4, R4 ROR 32')
+        self.assertEqual(
+            compute('MOVS R4, R4 ROR R5', {R4: 0xDEADBEEF, R5: 0xBADBAD01, }), {R4: 0xEF56DF77, R5: 0xBADBAD01, nf: 1, zf: 0, cf: 1,})
+        self.assertEqual(compute('MOVS R4, R4 RRX   ', {cf: 0, R4: 0xDEADBEEF, }), {
+                        cf: 1, R4: 0x6F56DF77, zf: 0, nf: 0})
+        self.assertEqual(compute('MOVS R4, R4 RRX   ', {cf: 1, R4: 0xDEADBEEF, }), {
+                        cf: 1, R4: 0xEF56DF77, zf: 0, nf: 1})
 
     def test_ADC(self):
         # §A8.8.1:                 ADC{S}{<c>}{<q>} {<Rd>,} <Rn>, #<const>