diff --git a/miasm/arch/arm/arch.py b/miasm/arch/arm/arch.py index 497d6d689..985e706da 100644 --- a/miasm/arch/arm/arch.py +++ b/miasm/arch/arm/arch.py @@ -1709,6 +1709,30 @@ def armtop(name, fields, args=None, alias=False): armop("isb", [bs8(0xF5), bs8(0x7F), bs8(0xF0), bs8(0x6F)]) armop("nop", [bs8(0xE3), bs8(0x20), bs8(0xF0), bs8(0)]) + +parallel_arith_name = { + 'Q': 0b01100010, + 'S': 0b01100001, + 'SH': 0b01100011, + 'U': 0b01100101, + 'UH': 0b01100111, + 'UQ': 0b01100110, +} +bs_parallel_arith = bs_name(l=8, name=parallel_arith_name) + +parallel_modarith_name = { + 0b0001 : 'ADD16', + 0b0011 : 'ADDSUBX', + 0b0101 : 'SUBADDX', + 0b0111 : 'SUB16', + 0b1001 : 'ADD8', + 0b1111 : 'SUB8', +} +bs_parallel_modarith = bs_mod_name(l=4, mn_mod=parallel_modarith_name) + +armop("arith", [bs_parallel_arith, rn, rd, bs('1111'), bs_parallel_modarith, rm], [rd, rn, rm]) + + class arm_widthm1(arm_imm, m_arg): def decode(self, v): self.expr = ExprInt(v+1, 32) diff --git a/miasm/arch/arm/sem.py b/miasm/arch/arm/sem.py index 981a50605..870da31d8 100644 --- a/miasm/arch/arm/sem.py +++ b/miasm/arch/arm/sem.py @@ -1285,6 +1285,97 @@ def uadd8(ir, instr, a, b, c): return e, [] +def uadd16(ir, instr, a, b, c): + e = [] + sums = [] + ges = [] + for i in range(0, 32, 16): + sums.append(b[i:i+16] + c[i:i+16]) + ges.append((b[i:i+16].zeroExtend(17) + c[i:i+16].zeroExtend(17))[16:17]) + + e.append(ExprAssign(a, ExprCompose(*sums))) + + for i, value in enumerate(ges): + e.append(ExprAssign(ge_regs[2 * i], value)) + e.append(ExprAssign(ge_regs[2 * i + 1], value)) + return e, [] + + +def uaddsubx(ir, instr, a, b, c): + e = [] + sums = [] + ges = [] + + + part1, part2 = b[16:32], c[0:16] + sums.append(part1 + part2) + ges.append((part1.zeroExtend(17) + part2.zeroExtend(17))[16:17]) + + part1, part2 = b[0:16], c[16:32] + sums.append(part1 - part2) + ges.append(ExprOp("FLAG_SIGN_SUB", part1, part2)) + + e.append(ExprAssign(a, ExprCompose(*sums[::-1]))) + + for i, value in enumerate(ges[::-1]): + e.append(ExprAssign(ge_regs[2 * i], value)) + e.append(ExprAssign(ge_regs[2 * i + 1], value)) + return e, [] + + +def sadd8(ir, instr, a, b, c): + e = [] + sums = [] + ges = [] + for i in range(0, 32, 8): + sums.append(b[i:i+8] + c[i:i+8]) + ges.append(ExprOp("FLAG_SIGN_SUB", ExprInt(0, 9), b[i:i+8].signExtend(9) + c[i:i+8].signExtend(9))) + + e.append(ExprAssign(a, ExprCompose(*sums))) + + for i, value in enumerate(ges): + e.append(ExprAssign(ge_regs[i], value)) + return e, [] + + +def sadd16(ir, instr, a, b, c): + e = [] + sums = [] + ges = [] + for i in range(0, 32, 16): + sums.append(b[i:i+16] + c[i:i+16]) + ges.append(ExprOp("FLAG_SIGN_SUB", ExprInt(0, 17), b[i:i+16].signExtend(17) + c[i:i+16].signExtend(17))) + + e.append(ExprAssign(a, ExprCompose(*sums))) + + for i, value in enumerate(ges): + e.append(ExprAssign(ge_regs[2 * i], value)) + e.append(ExprAssign(ge_regs[2 * i + 1], value)) + return e, [] + + +def saddsubx(ir, instr, a, b, c): + e = [] + sums = [] + ges = [] + + + part1, part2 = b[16:32], c[0:16] + sums.append(part1 + part2) + ges.append(ExprOp("FLAG_SIGN_SUB", ExprInt(0, 17), part1.signExtend(17) + part2.signExtend(17))) + + part1, part2 = b[0:16], c[16:32] + sums.append(part1 - part2) + ges.append(~ExprOp("FLAG_SIGN_SUB", part1, part2)) + + e.append(ExprAssign(a, ExprCompose(*sums[::-1]))) + + for i, value in enumerate(ges[::-1]): + e.append(ExprAssign(ge_regs[2 * i], value)) + e.append(ExprAssign(ge_regs[2 * i + 1], value)) + return e, [] + + def sel(ir, instr, a, b, c): e = [] cond = nf ^ of ^ ExprInt(1, 1) @@ -1641,6 +1732,11 @@ def add_condition_expr(ir, instr, cond, instr_ir, extra_ir): 'smlatb': smlatb, 'smlatt': smlatt, 'uadd8': uadd8, + 'uadd16': uadd16, + 'uaddsubx': uaddsubx, + 'sadd8': sadd8, + 'sadd16': sadd16, + 'saddsubx': saddsubx, 'sel': sel, } diff --git a/test/arch/arm/arch.py b/test/arch/arm/arch.py index 5aa619ea4..4e2ad1dc0 100644 --- a/test/arch/arm/arch.py +++ b/test/arch/arm/arch.py @@ -222,7 +222,8 @@ def u16swap(i): ('XXXXXXXX UXTAB R5, R2, R8 ROR 0x8', '7854e2e6'), - + ('XXXXXXXX UADD8 R1, R2, R3', + '931f52e6'), ('XXXXXXXX PKHBT R1, R2, R3 LSL 0x8', '131482e6'), diff --git a/test/arch/arm/unit/asm_test.py b/test/arch/arm/unit/asm_test.py new file mode 100644 index 000000000..6290819df --- /dev/null +++ b/test/arch/arm/unit/asm_test.py @@ -0,0 +1,74 @@ +from builtins import str +from builtins import object +import sys +import os + +from future.utils import viewitems + +from miasm.arch.arm.arch import mn_arm, base_expr, variable +from miasm.core import parse_asm +from miasm.expression.expression import * +from miasm.core import asmblock +from miasm.loader.strpatchwork import StrPatchwork +from miasm.analysis.machine import Machine +from miasm.jitter.csts import * + +reg_and_id = dict(mn_arm.regs.all_regs_ids_byname) + +class Asm_Test(object): + run_addr = 0x0 + + def __init__(self, jitter_engine): + self.myjit = Machine(self.arch_name).jitter(jitter_engine) + self.myjit.init_stack() + + def test_init(self): + pass + + def prepare(self): + pass + + def __call__(self): + self.prepare() + self.asm() + self.init_machine() + self.test_init() + self.run() + self.check() + + def run(self): + + self.myjit.init_run(self.run_addr) + self.myjit.continue_run() + + assert(self.myjit.pc == self.ret_addr) + + def asm(self): + blocks, loc_db = parse_asm.parse_txt( + mn_arm, self.arch_attrib, self.TXT, + loc_db = self.myjit.ir_arch.loc_db + ) + # fix shellcode addr + loc_db.set_location_offset(loc_db.get_name_location("main"), 0x0) + s = StrPatchwork() + patches = asmblock.asm_resolve_final(mn_arm, blocks, loc_db) + for offset, raw in viewitems(patches): + s[offset] = raw + + s = bytes(s) + self.assembly = s + + def check(self): + raise NotImplementedError('abstract method') + + +class Asm_Test(Asm_Test): + arch_name = "arml" + arch_attrib = "l" + ret_addr = 0x1330 + + def init_machine(self): + self.myjit.vm.add_memory_page(self.run_addr, PAGE_READ | PAGE_WRITE, self.assembly) + self.myjit.push_uint32_t(self.ret_addr) + self.myjit.add_breakpoint(self.ret_addr, lambda x:False) + diff --git a/test/arch/arm/unit/mn_parallel.py b/test/arch/arm/unit/mn_parallel.py new file mode 100644 index 000000000..f756ca43e --- /dev/null +++ b/test/arch/arm/unit/mn_parallel.py @@ -0,0 +1,367 @@ +#! /usr/bin/env python2 + +import sys + +from asm_test import Asm_Test + + +# Test from inspired from SimSoC arm tests + + +class Test_UADD8_1(Asm_Test): + MYSTRING = "test uadd8 1" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x026080fe + self.myjit.cpu.R2 = 0x0360fffe + + TXT = ''' + main: + UADD8 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x05c07ffc + assert self.myjit.cpu.ge0 == 1 + assert self.myjit.cpu.ge1 == 1 + assert self.myjit.cpu.ge2 == 0 + assert self.myjit.cpu.ge3 == 0 + + +class Test_UADD8_2(Asm_Test): + MYSTRING = "test uadd8 2" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x02fe01fc + self.myjit.cpu.R2 = 0xff04fe02 + + TXT = ''' + main: + UADD8 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x0102fffe + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_UADD16_1(Asm_Test): + MYSTRING = "test uadd16 1" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x0002fccc + self.myjit.cpu.R2 = 0xffff0222 + + TXT = ''' + main: + UADD16 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x0001feee + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_UADD16_2(Asm_Test): + MYSTRING = "test uadd16 2" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x11116666 + self.myjit.cpu.R2 = 0x22227777 + + TXT = ''' + main: + UADD16 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x3333dddd + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 0 + assert self.myjit.cpu.ge3 == 0 + + +class Test_UADD16_3(Asm_Test): + MYSTRING = "test uadd16 3" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0xabcd8000 + self.myjit.cpu.R2 = 0xffffffff + + TXT = ''' + main: + UADD16 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0xabcc7fff + assert self.myjit.cpu.ge0 == 1 + assert self.myjit.cpu.ge1 == 1 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_UADDSUBX_1(Asm_Test): + MYSTRING = "test uaddsubx 1" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0xbeefcafe + self.myjit.cpu.R2 = 0xcafefff1 + + TXT = ''' + main: + UADDSUBX R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0xbee00000 + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_UADDSUBX_2(Asm_Test): + MYSTRING = "test uaddsubx 2" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x12345678 + self.myjit.cpu.R2 = 0x56781234 + + TXT = ''' + main: + UADDSUBX R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x24680000 + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 0 + assert self.myjit.cpu.ge3 == 0 + + +class Test_SADD8_1(Asm_Test): + MYSTRING = "test sadd8 1" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x026080fe + self.myjit.cpu.R2 = 0x0360fffe + + TXT = ''' + main: + SADD8 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x05c07ffc + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_SADD8_2(Asm_Test): + MYSTRING = "test sadd8 2" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x02fe01fc + self.myjit.cpu.R2 = 0xff04fe02 + + TXT = ''' + main: + SADD8 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x0102fffe + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_SADD16_1(Asm_Test): + MYSTRING = "test sadd16 1" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x0002fccc + self.myjit.cpu.R2 = 0xffff0222 + + TXT = ''' + main: + SADD16 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x0001feee + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_SADD16_2(Asm_Test): + MYSTRING = "test sadd16 2" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x11116666 + self.myjit.cpu.R2 = 0x22227777 + + TXT = ''' + main: + SADD16 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x3333dddd + assert self.myjit.cpu.ge0 == 1 + assert self.myjit.cpu.ge1 == 1 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +class Test_SADD16_3(Asm_Test): + MYSTRING = "test sadd16 3" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0xabcd8000 + self.myjit.cpu.R2 = 0xffffffff + + TXT = ''' + main: + SADD16 R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0xabcc7fff + assert self.myjit.cpu.ge0 == 0 + assert self.myjit.cpu.ge1 == 0 + assert self.myjit.cpu.ge2 == 0 + assert self.myjit.cpu.ge3 == 0 + + +class Test_SADDSUBX_1(Asm_Test): + MYSTRING = "test saddsubx 1" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0xbeefcafe + self.myjit.cpu.R2 = 0xcafefff1 + + TXT = ''' + main: + SADDSUBX R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0xbee00000 + assert self.myjit.cpu.ge0 == 1 + assert self.myjit.cpu.ge1 == 1 + assert self.myjit.cpu.ge2 == 0 + assert self.myjit.cpu.ge3 == 0 + + +class Test_SADDSUBX_2(Asm_Test): + MYSTRING = "test saddsubx 2" + + def prepare(self): + self.myjit.ir_arch.loc_db.add_location("lbl_ret", self.ret_addr) + + def test_init(self): + self.myjit.cpu.R1 = 0x12345678 + self.myjit.cpu.R2 = 0x56781234 + + TXT = ''' + main: + SADDSUBX R0, R1, R2 + B lbl_ret + ''' + + def check(self): + assert self.myjit.cpu.R0 == 0x24680000 + assert self.myjit.cpu.ge0 == 1 + assert self.myjit.cpu.ge1 == 1 + assert self.myjit.cpu.ge2 == 1 + assert self.myjit.cpu.ge3 == 1 + + +if __name__ == "__main__": + [ + test(*sys.argv[1:])() for test in [ + Test_UADD8_1, + Test_UADD8_2, + Test_UADD16_1, + Test_UADD16_2, + Test_UADD16_3, + Test_UADDSUBX_1, + Test_UADDSUBX_2, + + Test_SADD8_1, + Test_SADD8_2, + Test_SADD16_1, + Test_SADD16_2, + Test_SADD16_3, + Test_SADDSUBX_1, + Test_SADDSUBX_2, + + ] + ] diff --git a/test/test_all.py b/test/test_all.py index a8a0d5991..2c2898897 100755 --- a/test/test_all.py +++ b/test/test_all.py @@ -105,6 +105,7 @@ def __init__(self, script, jitter ,*args, **kwargs): "aarch64/unit/mn_ubfm.py", "msp430/sem.py", "mips32/unit/mn_bcc.py", + "arm/unit/mn_parallel.py", ]: for jitter in ArchUnitTest.jitter_engines: if jitter in blacklist.get(script, []):