diff options
| author | serpilliere <serpilliere@users.noreply.github.com> | 2017-07-24 11:19:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-07-24 11:19:05 +0200 |
| commit | b088e965b09abedad4e62664c05b06a65522a80e (patch) | |
| tree | 8d928c5641900d425896a26bcca580ee28952ff0 | |
| parent | 051c1d2d7f1c58effd716e35f7b6897dcbe45488 (diff) | |
| parent | 75da46490f10f3dae861dbf9b551f713fbb49e08 (diff) | |
| download | miasm-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.py | 229 | ||||
| -rw-r--r-- | test/arch/aarch64/arch.py | 4 |
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"), + ] |