about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorserpilliere <serpilliere@users.noreply.github.com>2017-07-24 11:19:05 +0200
committerGitHub <noreply@github.com>2017-07-24 11:19:05 +0200
commitb088e965b09abedad4e62664c05b06a65522a80e (patch)
tree8d928c5641900d425896a26bcca580ee28952ff0
parent051c1d2d7f1c58effd716e35f7b6897dcbe45488 (diff)
parent75da46490f10f3dae861dbf9b551f713fbb49e08 (diff)
downloadmiasm-b088e965b09abedad4e62664c05b06a65522a80e.tar.gz
miasm-b088e965b09abedad4e62664c05b06a65522a80e.zip
Merge pull request #589 from commial/fix/aarch64-imm-decode
Fix/aarch64 imm decode
-rw-r--r--miasm2/arch/aarch64/arch.py229
-rw-r--r--test/arch/aarch64/arch.py4
2 files changed, 209 insertions, 24 deletions
diff --git a/miasm2/arch/aarch64/arch.py b/miasm2/arch/aarch64/arch.py
index 7c8f22ef..09af57b1 100644
--- a/miasm2/arch/aarch64/arch.py
+++ b/miasm2/arch/aarch64/arch.py
@@ -1066,21 +1066,204 @@ class aarch64_gpreg_sftimm(reg_noarg, m_arg):
 
 
 def ror(value, amount, size):
-    return (value >> amount) | (value << (size - amount))
+    mask = (1 << size) - 1
+    return ((value >> amount) | (value << (size - amount))) & mask
 
 
 def rol(value, amount, size):
-    return (value << amount) | (value >> (size - amount))
+    mask = (1 << size) - 1
+    return ((value << amount) | (value >> (size - amount)) & mask)
 
-UINTS = {32: uint32, 64: uint64}
+# This implementation is inspired from ARM ISA v8.2
+# Exact Reference name:
+# "ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile"
 
+class ReservedValue(Exception):
+    """Reserved Value, should not happen"""
+    pass
+
+class NotEncodable(Exception):
+    """Instruction is not encodable"""
+    pass
+
+class bits(object):
+    """Stand for ARM ASL 'bits' type, ie. a bit vector"""
+
+    __slots__ = ["size", "value"]
+
+    def __init__(self, size, value):
+        """Instanciate a bitvector of size @size with value @value"""
+        self.size = size
+        if value & self.mask != value:
+            raise ValueError("Value %s is too large for %d bits",
+                             hex(value), size)
+        self.value = value
 
-def imm_to_imm_rot_form(value, size):
-    for i in xrange(0, size):
-        mod_value = int(rol(value, i, size))
-        if (mod_value + 1) & mod_value == 0:
+    def concat_left(self, other_bits):
+        """Return a new bits instance for @other_bits . self"""
+        return bits(self.size + other_bits.size,
+                    self.value | (other_bits.value << self.size))
+
+    @property
+    def mask(self):
+        return (1 << self.size) - 1
+
+    def __invert__(self):
+        return bits(self.size, self.value ^ self.mask)
+
+    def __int__(self):
+        return self.value
+
+    def __and__(self, other_bits):
+        assert other_bits.size == self.size
+        return bits(self.size, self.value & other_bits.value)
+
+    def __eq__(self, other_bits):
+        return all((self.size == other_bits.size,
+                    self.value == other_bits.value))
+
+    def __getitem__(self, info):
+        if isinstance(info, slice):
+            start = info.start if info.start else 0
+            stop = info.stop if info.stop else self.value
+            if info.step is not None:
+                raise RuntimeError("Not implemented")
+            mask = (1 << stop) - 1
+            return bits(stop - start,
+                        (self.value >> start) & mask)
+        else:
+            raise RuntimeError("Not implemented")
+
+    @property
+    def pop_count(self):
+        "Population count: number of bit set"
+        count = 0
+        value = self.value
+        while (value > 0):
+            if value & 1 == 1:
+                count += 1
+            value >>= 1
+        return count
+
+    def __str__(self):
+        return "'%s'" % "".join('1' if self.value & (1 << i) else '0'
+                                for i in reversed(xrange(self.size)))
+
+# From J1-6035
+def HighestSetBit(x):
+    for i in reversed(xrange(x.size)):
+        if x.value & (1 << i):
             return i
-    return None
+    return - 1
+
+# From J1-6037
+def Ones(N):
+    return bits(N, (1 << N) - 1)
+
+# From J1-6038
+def ROR(x, shift):
+    if shift == 0:
+        return x
+    return bits(x.size, ror(UInt(x), shift, x.size))
+
+# From J1-6038
+def Replicate(x, N):
+    assert N % x.size == 0
+    new = x
+    while new.size < N:
+        new = new.concat_left(x)
+    return new
+
+# From J1-6039
+def UInt(x):
+    return int(x)
+
+# From J1-6039
+def ZeroExtend(x, N):
+    assert N >= x.size
+    return bits(N, x.value)
+
+# From J1-5906
+def DecodeBitMasks(M, immN, imms, immr, immediate):
+    """
+    @M: 32 or 64
+    @immN: 1-bit
+    @imms: 6-bit
+    @immr: 6-bit
+    @immediate: boolean
+    """
+    len_ = HighestSetBit((~imms).concat_left(immN))
+    if len_ < 1:
+        raise ReservedValue()
+    assert M >= (1 << len_)
+
+    levels = ZeroExtend(Ones(len_), 6)
+
+    if immediate and (imms & levels) == levels:
+        raise ReservedValue()
+    S = UInt(imms & levels);
+    R = UInt(immr & levels);
+
+    esize = 1 << len_
+    welem = ZeroExtend(Ones(S + 1), esize)
+    wmask = Replicate(ROR(welem, R), M)
+
+    # For now, 'tmask' is unused:
+    #
+    # diff = S - R;
+    # d = UInt(bits(len_, diff))
+    # telem = ZeroExtend(Ones(d + 1), esize)
+    # tmask = Replicate(telem, M)
+
+    return wmask, None
+
+# EncodeBitMasks doesn't have any equivalent in ARM ASL shared functions
+# This implementation "reverses" DecodeBitMasks flow
+def EncodeBitMasks(wmask):
+    # Find replicate
+    M = wmask.size
+    for i in xrange(1, M + 1):
+        if M % i != 0:
+            continue
+        if wmask == Replicate(wmask[:i], M):
+            break
+    else:
+        raise NotEncodable
+
+    # Find ROR value: welem is only '1's
+    welem_after_ror = wmask[:i]
+    esize = welem_after_ror.size
+    S = welem_after_ror.pop_count - 1
+    welem = ZeroExtend(Ones(S + 1), esize)
+    for i in xrange(welem_after_ror.size):
+        if ROR(welem, i) == welem_after_ror:
+            break
+    else:
+        raise NotEncodable
+    R = i
+
+    # Find len value
+    for i in xrange(M):
+        if (1 << i) == esize:
+            break
+    else:
+        raise NotEncodable
+    len_ = i
+    levels = ZeroExtend(Ones(len_), 6)
+    levels = UInt(levels)
+
+    if len_ == 6:
+        # N = 1
+        immn = 1
+        imms = S
+    else:
+        # N = 0, NOT(imms) have to be considered
+        immn = 0
+        mask = (1 << ((6 - len_ - 1))) - 1
+        mask <<= (len_ + 1)
+        imms = S | mask
+    immr = R
+    return immr, imms, immn
 
 
 class aarch64_imm_nsr(aarch64_imm_sf, m_arg):
@@ -1088,9 +1271,14 @@ class aarch64_imm_nsr(aarch64_imm_sf, m_arg):
 
     def decode(self, v):
         size = 64 if self.parent.sf.value else 32
-        mask = UINTS[size]((1 << (v + 1)) - 1)
-        mask = ror(mask, self.parent.immr.value, size)
-        self.expr = m2_expr.ExprInt(mask, size)
+        bitmask, _ = DecodeBitMasks(size,
+                                    bits(1, self.parent.immn.value),
+                                    bits(6, v),
+                                    bits(6, self.parent.immr.value),
+                                    True
+        )
+        self.expr = m2_expr.ExprInt(UInt(bitmask),
+                                    size)
         return True
 
     def encode(self):
@@ -1102,20 +1290,13 @@ class aarch64_imm_nsr(aarch64_imm_sf, m_arg):
         if value == 0:
             return False
 
-        index = imm_to_imm_rot_form(value, self.expr.size)
-        if index == None:
-            return False
-        power = int(rol(value, index, self.expr.size)) + 1
-        length = None
-        for i in xrange(self.expr.size):
-            if 1 << i == power:
-                length = i
-                break
-        if length is None:
+        try:
+            immr, imms, immn = EncodeBitMasks(bits(self.expr.size, value))
+        except NotEncodable:
             return False
-        self.parent.immr.value = index
-        self.value = length - 1
-        self.parent.immn.value = 1 if self.expr.size == 64 else 0
+        self.parent.immr.value = immr
+        self.parent.immn.value = immn
+        self.value = imms
         return True
 
 
diff --git a/test/arch/aarch64/arch.py b/test/arch/aarch64/arch.py
index ec978024..8364fcf1 100644
--- a/test/arch/aarch64/arch.py
+++ b/test/arch/aarch64/arch.py
@@ -1786,6 +1786,10 @@ reg_tests_aarch64 = [
      "E003809A"),
     ("XXXXXXXX    ADD        X0, SP, XZR UXTX 0x0",
      "E0633F8B"),
+
+    ("XXXXXXXX    ORR        X8, 0x0, 0x1000100010001",
+     "E88300B2"),
+
 ]