def do_st_abs(reg, addr, size): if self.is_io(addr): st.op = IMPURE if size == 4: op = IOOUT32 elif size == 2: op = IOOUT16 else: op = IOOUT st.expr = Expr(op, [SSADef.cur(ctx, reg), addr]) st.expr.dont_propagate = True st.expr.dont_eliminate = True st.dest = [] else: st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, reg)]) if size == 4: pref = 'Mw' elif size == 2: pref = 'Mh' elif size == 1: pref = 'M' else: raise InternalError('unhandled size ' + str(size)) st.dest = [SSADef(ctx, pref, addr)]
def chain_flags_ror(st, reg1, res): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SHFLAGS_N, [res])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(NOT, [res])) st1.chain(ctx, st2) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(AND, [reg1, 1])) st2.chain(ctx, st3) return st3
def do_st_xy(src, addr, reg): st.dest = [] st.op = IMPURE if self.is_io(addr): st.expr = Expr(IOOUT, [Expr(ADD, [addr, SSADef.cur(ctx, reg)]), SSADef.cur(ctx, src)]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.expr = Expr(STORE, [SSADef.cur(ctx, src), addr, SSADef.cur(ctx, reg)])
def chain_flags_incdec(st, reg): st1 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(NOT, [reg]) st2 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(COMPARE_GE, [reg, 0x80]) return st
def chain_flags_bit(st, mem): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(BITFLAGS_N, [SSADef.cur(ctx, 'M', mem)]) st2 = SSAStatement(SSADef(ctx, 'V'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(BITFLAGS_V, [SSADef.cur(ctx, 'M', mem)]) return st
def chain_flags_or(st, reg, op): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(ORFLAGS_N, [reg, op]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(ORFLAGS_Z, [reg, op]) return st
def chain_flags_sbb(st, reg1, reg2, reg3): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SBBFLAGS_N, [reg1, reg2, reg3])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(SBBFLAGS_Z, [reg1, reg2, reg3])) st1.chain(ctx, st2) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(SBBFLAGS_C, [reg1, reg2, reg3])) st2.chain(ctx, st3) st4 = SSAStatement(SSADef(ctx, 'V'), ASGN, Expr(SBBFLAGS_V, [reg1, reg2, reg3])) st3.chain(ctx, st4) return st4
def chain_flags_shr(st, reg, res): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st1.expr = Expr(SHFLAGS_N, [res]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st1.chain(ctx, st2) st2.expr = Expr(NOT, [res]) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN) st2.chain(ctx, st3) st3.expr = Expr(AND, [reg, 1]) return st3
def do_st_abs(reg): if self.is_io(abs()): st.op = IMPURE st.dest = [] st.expr = Expr(IOOUT, [abs(), SSADef.cur(ctx, reg)]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.dest = [SSADef(ctx, 'M', abs())] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, reg)])
def chain_flags_ld(st, reg): op = SSADef.cur(ctx, 'A') st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(COMPARE_GE, [Expr(VAR, [op]), 0x80]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(NOT, [op]) return st
def do_ld_xy(dst, addr, reg): nonlocal st st.dest = [SSADef(ctx, dst)] st.op = ASGN if self.is_io(addr): st.expr = Expr(IOIN, [Expr(ADD, [addr, SSADef.cur(ctx, reg)])]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.expr = Expr(LOAD, [addr, SSADef.cur(ctx, reg)]) st = chain_flags_ld(st, dst)
def do_ld_abs(reg): nonlocal st st.dest = [SSADef(ctx, reg)] st.op = ASGN if self.is_io(abs()): st.expr = Expr(IOIN, [abs()]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', abs())]) st = chain_flags_ld(st, reg)
def do_st_reg(src, off, reg, size): st.dest = [] st.op = IMPURE # XXX: convert to IOOUT after constant prop if size == 4: op = STORE32 elif size == 2: op = STORE16 elif size == 1: op = STORE else: raise InternalError('unhandled size ' + str(size)) st.expr = Expr(op, [SSADef.cur(ctx, src), off, SSADef.cur(ctx, reg)])
def do_ld_reg(dst, off, reg, size): nonlocal st st.op = ASGN # XXX: convert to IOIN after constant prop if size == 1: st.expr = Expr(LOAD, [off, SSADef.cur(ctx, reg)]) elif size == 2: st.expr = Expr(LOAD16, [off, SSADef.cur(ctx, reg)]) elif size == 4: st.expr = Expr(LOAD32, [off, SSADef.cur(ctx, reg)]) else: raise InternalError('unhandled size ' + str(size)) st.dest = [SSADef(ctx, dst)]
def chain_flags_ldimm(st, imm): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 if imm > 0x80: st.expr = Expr(CONST, [1]) else: st.expr = Expr(CONST, [0]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st2) st = st2 if imm: st.expr = Expr(CONST, [0]) else: st.expr = Expr(CONST, [1]) return st
def creg(num): nonlocal sp if num == 13: return Expr(AUTO, [sp, -1]) elif num == 15: return insn.addr + 8 else: return SSADef.cur(ctx, 'R'+str(num))
def do_branch(flag, positive): nonlocal next, st if insn.fake_branch >= 0: next = [insn.next[insn.fake_branch]] st.op = ASGN st.expr = Expr(NOP, [0]) else: st.op = BRANCH_COND st.expr = Expr(VAR if positive else NOT, [SSADef.cur(ctx, flag)]) st.dest = []
def do_ld_abs(reg, addr, size): nonlocal st st.op = ASGN if self.is_io(addr): if size == 1: op = IOIN elif size == 2: op = IOIN16 else: op = IOIN32 st.expr = Expr(op, [addr]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: if size == 4: st.expr = Expr(VAR, [SSADef.cur(ctx, 'Mw', addr)]) elif size == 2: st.expr = Expr(VAR, [SSADef.cur(ctx, 'Mh', addr)]) elif size == 1: st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', addr)]) else: raise InternalError('unhandled size ' + str(size)) st.dest = [SSADef(ctx, reg)]
def emit_flags_subimm(st, reg, imm): st.dest = [SSADef(ctx, 'C')] st.op = ASGN st.expr = Expr(COMPARE_GE, [SSADef.cur(ctx, reg), imm]) st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(COMPARE_LT, [SSADef.cur(ctx, reg), imm])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(COMPARE_EQ, [SSADef.cur(ctx, reg), imm])) st1.chain(ctx, st2) return st2
def do_ld_stack(dst, off, size): nonlocal sp, st st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 's', off+sp)]) st.dest = [SSADef(ctx, dst)]
def do_st_stack(src, off, size): nonlocal sp, st st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, src)]) st.dest = [SSADef(ctx, 's', off+sp)]
def translate(self, ctx, insn, sp, end_bp, bp): # normally, add() will follow the flow of the machine code instructions; # if we know better (such as with branches with constant conditions), we # can put a list of successor instructions here next = None st = SSAStatement() debug(SSA, 2, 'translating', insn, hex(insn.bytes[0]), 'to', st.num) opc = insn.bytes[0] if insn == None: return None st_start = st self.ssa_for_insn[insn] = st st.insn = insn if len(insn.comefrom) > 1: debug(SSA, 3, 'phiing') for g in ctx.local_indices.values(): st.dest = [SSADef(ctx, g.type, g.addr)] st.op = ASGN st.expr = Expr(PHI, [g]) for h in insn.comefrom: if h in self.last_ssa_for_insn: #print('reaching from', self.last_ssa_for_insn[h], [str(x) + '(' + repr(x) + ')' for x in self.last_ssa_for_insn[h].reaching]) for i in self.last_ssa_for_insn[h].reaching: if i.type == g.type and i.addr == g.addr and not i in st.expr.ops: st.expr.ops += [i] st1 = SSAStatement() st.chain(ctx, st1) st = st1 def rot_imm(imm8, rs): return ((imm8 >> rs * 2) | (imm8 << (32 - rs * 2))) & 0xffffffff def do_ld_abs(reg, addr, size): nonlocal st st.op = ASGN if self.is_io(addr): if size == 1: op = IOIN elif size == 2: op = IOIN16 else: op = IOIN32 st.expr = Expr(op, [addr]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: if size == 4: st.expr = Expr(VAR, [SSADef.cur(ctx, 'Mw', addr)]) elif size == 2: st.expr = Expr(VAR, [SSADef.cur(ctx, 'Mh', addr)]) elif size == 1: st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', addr)]) else: raise InternalError('unhandled size ' + str(size)) st.dest = [SSADef(ctx, reg)] def do_ld_reg(dst, off, reg, size): nonlocal st st.op = ASGN # XXX: convert to IOIN after constant prop if size == 1: st.expr = Expr(LOAD, [off, SSADef.cur(ctx, reg)]) elif size == 2: st.expr = Expr(LOAD16, [off, SSADef.cur(ctx, reg)]) elif size == 4: st.expr = Expr(LOAD32, [off, SSADef.cur(ctx, reg)]) else: raise InternalError('unhandled size ' + str(size)) st.dest = [SSADef(ctx, dst)] def do_st_abs(reg, addr, size): if self.is_io(addr): st.op = IMPURE if size == 4: op = IOOUT32 elif size == 2: op = IOOUT16 else: op = IOOUT st.expr = Expr(op, [SSADef.cur(ctx, reg), addr]) st.expr.dont_propagate = True st.expr.dont_eliminate = True st.dest = [] else: st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, reg)]) if size == 4: pref = 'Mw' elif size == 2: pref = 'Mh' elif size == 1: pref = 'M' else: raise InternalError('unhandled size ' + str(size)) st.dest = [SSADef(ctx, pref, addr)] def do_st_reg(src, off, reg, size): st.dest = [] st.op = IMPURE # XXX: convert to IOOUT after constant prop if size == 4: op = STORE32 elif size == 2: op = STORE16 elif size == 1: op = STORE else: raise InternalError('unhandled size ' + str(size)) st.expr = Expr(op, [SSADef.cur(ctx, src), off, SSADef.cur(ctx, reg)]) def do_ld_stack(dst, off, size): nonlocal sp, st st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 's', off+sp)]) st.dest = [SSADef(ctx, dst)] def do_st_stack(src, off, size): nonlocal sp, st st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, src)]) st.dest = [SSADef(ctx, 's', off+sp)] def creg(num): nonlocal sp if num == 13: return Expr(AUTO, [sp, -1]) elif num == 15: return insn.addr + 8 else: return SSADef.cur(ctx, 'R'+str(num)) def get_rm(): if insn.shift == 0: op = SHL elif insn.shift == 1: op = SHR elif insn.shift == 2: op = ASR else: op = ROR if insn.shift_rot == 1: # rs return Expr(op, [creg(insn.rm), creg(insn.rs)]) else: # imm return Expr(op, [creg(insn.rm), insn.shift_bits]) if insn.bytes[0] != OPC_OUTOFRANGE and insn.cond < 0xe or insn.artificial_branch != -1: debug(SSA, 5, "conditional", insn, hex(insn.artificial_branch)) # conditional st.op = BRANCH_COND if insn.cond == 0: st.expr = Expr(VAR, [SSADef.cur(ctx, 'Z')]) elif insn.cond == 1: st.expr = Expr(NOT, [SSADef.cur(ctx, 'Z')]) elif insn.cond == 2: st.expr = Expr(VAR, [SSADef.cur(ctx, 'C')]) elif insn.cond == 3: st.expr = Expr(NOT, [SSADef.cur(ctx, 'C')]) elif insn.cond == 4: st.expr = Expr(VAR, [SSADef.cur(ctx, 'N')]) elif insn.cond == 5: st.expr = Expr(NOT, [SSADef.cur(ctx, 'N')]) elif insn.cond == 8: st.expr = Expr(AND, [SSADef.cur(ctx, 'C'), Expr(NOT, [SSADef.cur(ctx, 'Z')])]) elif insn.cond == 9: st.expr = Expr(OR, [Expr(NOT, [SSADef.cur(ctx, 'C')]), SSADef.cur(ctx, 'Z')]) elif insn.cond == 0xa: st.expr = Expr(COMPARE_EQ, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')]) elif insn.cond == 0xb: st.expr = Expr(COMPARE_NE, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')]) elif insn.cond == 0xc: st.expr = Expr(AND, [ Expr(NOT, [SSADef.cur(ctx, 'Z')]), Expr(COMPARE_EQ, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')]) ]) elif insn.cond == 0xd: st.expr = Expr(OR, [ SSADef.cur(ctx, 'Z'), Expr(COMPARE_NE, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')]) ]) else: raise InternalError('unsupported condition') assert(insn.op & 0xf0 == 0xa0 or insn.artificial_branch != -1) if insn.bytes[0] == OPC_OUTOFRANGE: st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['thunk', insn.addr]) elif insn.cond == 0xf: # NV predicate debug(SSA, 5, "NV predicate") st.dest = [] st.op = ASGN st.expr = Expr(NOP, [0]) elif insn.op & 0xf0 == 0xa0: # B debug(SSA, 5, "branch") if insn.cond == 0xe: debug(SSA, 5, "unconditional branch") st.op = ASGN st.dest = [] st.expr = Expr(NOP, [0]) elif insn.op & 0xf1 == 0xe0: # MCR debug(SSA, 5, "mcr") st.op = IMPURE st.dest = [] st.expr = Expr(INTRINSIC, ['mcr']) elif insn.op & 0xf1 == 0xe1: # MRC debug(SSA, 5, "mrc") st.op = ASGN st.dest = [SSADef(ctx, 'R'+str(insn.rd))] st.expr = Expr(INTRINSIC, ['mrc']) elif insn.op & 0xc0 == 0x40: # LDR/STR rd,[rn,+-#imm12 / rm <> shift] pre/post if insn.op & 0x20: # register offset if insn.op & 0x08 == 0x08: off = get_rm() else: off = Expr(SUB, [0, get_rm()]) else: # immediate offset if insn.op & 0x08 == 0x08: off = insn.imm12 else: off = -insn.imm12 if insn.op & 0x04 == 0x04: size = 1 else: size = 4 if insn.fixed_mem != -1: assert(insn.rn != 13) debug(SSA, 6, 'transing fixed mem insn', insn) if insn.op & 1: do_ld_abs('R'+str(insn.rd), insn.fixed_mem, size) else: do_st_abs('R'+str(insn.rd), insn.fixed_mem, size) elif insn.fixed_stack != -1: debug(SSA, 6, 'transing fixed stack insn', insn) if insn.op & 1: do_ld_stack('R'+str(insn.rd), insn.fixed_stack-sp, size) else: do_st_stack('R'+str(insn.rd), insn.fixed_stack-sp, size) else: if insn.op & 1 == 1 and insn.rd == 15: # PC load if insn.rn == 15: # decoded already in insn.py st.dest = [] st.op = ASGN st.expr = Expr(NOP, [0]) else: st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['set_pc', insn.rn, off]) else: if insn.op & 0x10: # pre indexing noff = off else: noff = 0 if insn.rn == 15: if insn.op & 1: do_ld_abs('R'+str(insn.rd), insn.addr + 8 + noff, size) else: do_st_abs('R'+str(insn.rd), insn.addr + 8 + noff, size) elif insn.rn == 13: if insn.op & 1: do_ld_stack('R'+str(insn.rd), noff, size) else: do_st_stack('R'+str(insn.rd), noff, size) else: if insn.op & 1: do_ld_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), size) else: do_st_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), size) if insn.op & 2 == 2 or insn.op & 0x10 == 0: # write back or post indexing if insn.rn == 13: sp += off else: st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(ADD, [creg(insn.rn), off]) st.dest = [SSADef(ctx, 'R'+str(insn.rn))] elif insn.op & 0xe4 == 4 and insn.imm8 & 0x90 == 0x90: # LDRH/STRH rd, [rn, +-immWEIRD] imm = insn.rm | (insn.rs >> 4) if insn.op & 0x08 == 0: imm = -imm if insn.fixed_mem != -1: assert(insn.rn != 13) debug(SSA, 6, 'transing fixed mem insn', insn) if insn.op & 1: do_ld_abs('R'+str(insn.rd), insn.fixed_mem, 2) else: do_st_abs('R'+str(insn.rd), insn.fixed_mem, 2) else: if insn.op & 0x10: # pre indexing noff = imm else: noff = 0 if insn.rn == 13: if insn.op & 1: do_ld_stack('R'+str(insn.rd), noff, 2) else: do_st_stack('R'+str(insn.rd), noff, 2) else: if insn.op & 1: do_ld_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), 2) else: do_st_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), 2) if insn.op & 2: # write back st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(ADD, [creg(insn.rn), imm]) st.dest = [SSADef(ctx, 'R'+str(insn.rn))] elif insn.op == 0x32: # MSR CPSR_f, rm debug(SSA, 5, "MSR CPSR_f, rm") st.op = IMPURE st.dest = [] st.expr = Expr(INTRINSIC, ['msr_cpsr_f', creg(insn.rm)]) elif insn.bytes[0] & 0x0fbf0fff == 0x010f0000: # MRS st.op = ASGN st.expr = Expr(INTRINSIC, ['mrs', insn.op & 4]) st.dest = [SSADef(ctx, 'R'+str(insn.rd))] elif insn.bytes[0] & 0x0fbffff0 == 0x0129f000: # MSR st.op = IMPURE st.expr = Expr(INTRINSIC, ['msr', insn.op & 4, creg(insn.rm)]) st.dest = [] elif insn.op & 0xf0 == 0xb0: # BL off24 st.expr = Expr(ARGS, [insn.addr + 8 + insn.off24 * 4] + self.fun_args(ctx, insn.next[1], st, sp)) st.dest = self.fun_returns(ctx, insn.next[1], st) st.op = CALL elif insn.op & 0xe0 == 0x80: # LDM/STM # XXX: PSR/force user? off = 0 if insn.op & 0x08 == 0x08: inc = 4 regs = range(0, 16) else: inc = -4 regs = range(15, -1, -1) st.op = None do_return = False for i in regs: if insn.reglist & (1 << i): if insn.op & 0x10 == 0x10: # pre indexing off += inc if st.op != None: st1 = SSAStatement() st.chain(ctx, st1) st = st1 if insn.op & 1: # LDM if i == 15: # XXX: only if [rn,off] is r14 do_return = True elif insn.rn == 13: do_ld_stack('R'+str(i), off, 4) else: do_ld_reg('R'+str(i), off, 'R'+str(insn.rn), 4) else: if insn.rn == 13: do_st_stack('R'+str(i), off, 4) else: do_st_reg('R'+str(i), off, 'R'+str(insn.rn), 4) if insn.op & 0x10 != 0x10: # post indexing off += inc if insn.op & 2 == 2: # write back if insn.rn == 13: sp += off if end_bp == 0: end_bp = sp else: if st.op != None: st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(ADD, [creg(insn.rn), off]) st.dest = [SSADef(ctx, 'R'+str(insn.rn))] if do_return: if st.op != None: st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = RETURN st.expr = None st.dest = [] elif insn.bytes[0] & 0x0ffffff0 == 0x012fff10: # BX rm if insn.rm == 14: # XXX: only if R14 is unassigned st.dest = [] st.op = RETURN st.expr = None else: st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['bx', creg(insn.rm)]) st.add_comment('XXX: indirect jump not implemented yet') elif insn.bytes[0] & 0xffffff0 == 0x012fff30: # BLX rm st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['blx', creg(insn.rm)]) st.add_comment('XXX: indirect call not implemented yet') elif insn.bytes[0] & 0x0f900090 == 0x01000080: # smul/smla op = (insn.op >> 1) & 3 x = (insn.imm8 >> 5) & 1 y = (insn.imm8 >> 6) & 1 if op == 0 or op == 3: m1 = creg(insn.rm) m2 = creg(insn.rs) if x == 0: m1 = Expr(AND, [m1, 0xffff]) else: m1 = Expr(SHR, [m1, 16]) if y == 0: m2 = Expr(AND, [m2, 0xffff]) else: m2 = Expr(SHR, [m2, 16]) st.op = ASGN st.expr = Expr(MUL32, [m1, m2]) if op == 0: # smla st.expr = Expr(ADD, [st.expr, creg(insn.rn)]) st.dest = [SSADef(ctx, 'R'+str(insn.rd))] else: debug(SSA, 2, "unimplemented smul", insn) st.op = ASGN st.expr = Expr(INTRINSIC, ["smulw", op, x, y, creg(insn.rm), creg(insn.rs)]) st.dest = [SSADef(ctx, 'R'+str(insn.rd))] elif insn.bytes[0] & 0x0e000010 == 0x06000010: # media insn # XXX: untested, implemented inadvertently debug(SSA, 2, "unimplemented media instruction", insn) st.op = ASGN st.expr = Expr(INTRINSIC, ["media_insn", insn.bytes[0], creg(insn.rm)]) st.dest = [SSADef(ctx, 'R'+str(insn.rd))] elif insn.bytes[0] & 0x0f9000f0 == 0x01000050: # sat add/sub debug(SSA, 2, "unimplemented saturated add/sub", insn) st.op = ASGN st.expr = Expr(INTRINSIC, ["qaddsub", insn.bytes[0], creg(insn.rn), creg(insn.rm)]) st.dest = [SSADef(ctx, 'R'+str(insn.rd))] elif insn.op & 0xc0 == 0x00: # ALU rd, rn, #imm8 <> rs / rm <> shift alu_op = (insn.op >> 1) & 0xf debug(SSA, 5, "alu op", alu_op) if insn.rd == 13 and alu_op in [2, 4]: assert(insn.op & 0x20 == 0x20) # immediate if alu_op == 4: # XXX: hack: assume conditional adds to SP only occur in epilogs and ignore them # otherwise our stack pointer tracking gets mangled if insn.cond == 0xe: sp += rot_imm(insn.imm8, insn.rs) else: sp -= rot_imm(insn.imm8, insn.rs) st.op = ASGN st.dest = [] st.expr = Expr(NOP, [sp]) else: st.op = None if insn.op & 0x20 == 0: imm = get_rm() else: imm = rot_imm(insn.imm8, insn.rs) if alu_op in [2, 3, 6, 7, 0xa]: op = SUB op_c = COMPARE_GE op_z = COMPARE_EQ op_n = COMPARE_LT op_v = SUBFLAGS_V elif alu_op == 0 or alu_op == 8 or alu_op == 0xe: op = AND op_c = ANDFLAGS_C op_z = ANDFLAGS_Z op_n = ANDFLAGS_N op_v = None elif alu_op == 1 or alu_op == 9: op = EOR op_c = EORFLAGS_C op_z = EORFLAGS_Z op_n = EORFLAGS_N op_v = None elif alu_op == 4 or alu_op == 5 or alu_op == 0xb: op = ADD op_c = ADDFLAGS_C op_z = ADDFLAGS_Z op_n = ADDFLAGS_N op_v = ADDFLAGS_V elif alu_op == 0xc: op = OR op_c = ORFLAGS_C op_z = ORFLAGS_Z op_n = ORFLAGS_N op_v = None else: # MOV, MVN op = CONST op_c = MOVFLAGS_C op_z = MOVFLAGS_Z op_n = MOVFLAGS_N op_v = None reverse = False if alu_op == 3 or alu_op == 7: # RSB, RSC reverse = True if alu_op == 0xf or alu_op == 0xe: # BIC, MVN imm = Expr(INV, [imm]) if op == CONST: if insn.op & 0x20 == 0: st.expr = imm else: st.expr = Expr(CONST, [imm]) else: if insn.rn == 13 and insn.op & 0x20 == 0x20 and alu_op == 4: st.expr = Expr(AUTO, [sp + imm, -1]) # XXX: may be better to do this on CALL if sp + imm < bp: bp = sp + imm elif insn.rn == 13 and insn.op & 0x20 == 0x20 and alu_op == 2: st.expr = Expr(AUTO, [sp - imm, -1]) if sp - imm < bp: bp = sp - imm else: op1 = creg(insn.rn) if reverse: op2 = op1 op1 = imm else: op2 = imm if alu_op == 5: # ADC st.expr = Expr(op, [op1, op2, SSADef.cur(ctx, 'C')]) elif alu_op == 6 or alu_op == 7: # SBC, RSC st.expr = Expr(ADD, [Expr(op, [op1, op2, 1]), SSADef.cur(ctx, 'C')]) else: st.expr = Expr(op, [op1, op2]) if alu_op in [0, 1, 2, 3, 4, 5, 6, 7, 0xc, 0xd, 0xe, 0xf] and insn.rd != 15: st.op = ASGN st.dest = [SSADef(ctx, 'R'+str(insn.rd))] if insn.rd == 15: st.op = IMPURE st.expr = Expr(INTRINSIC, ['set_pc', st.expr]) st.dest = [] if alu_op == 0xb and not (insn.op & 1): # clz # XXX: complete guesswork, too lazy too look it up st.op = ASGN st.expr = Expr(INTRINSIC, ['clz', creg(insn.rn)]) st.dest = [SSADef(ctx, 'R'+str(insn.rd))] elif insn.op & 1: # set flags alu_expr = st.expr if st.op == ASGN: st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(op_c, copy(alu_expr.ops)) st.dest = [SSADef(ctx, 'C')] st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(op_z, copy(alu_expr.ops)) st.dest = [SSADef(ctx, 'Z')] st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(op_n, copy(alu_expr.ops)) st.dest = [SSADef(ctx, 'N')] if op_v: st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.op = ASGN st.expr = Expr(op_v, copy(alu_expr.ops)) st.dest = [SSADef(ctx, 'V')] else: raise InternalError('unknown op ' + hex(insn.op)) # all current indices are reaching, with the exception of anything # below the stack pointer st.reaching = [] for i in ctx.local_indices.values(): if not (i.type == 's' and i.addr < 0): #True: #i.type != 's':# or i.addr > sp: st.reaching += [i] self.last_ssa_for_insn[insn] = st debug(SSA, 6, "st_end in translate", st) return (st_start, st, sp, bp, end_bp, next)
def translate(self, ctx, insn, sp, end_bp, bp): debug(SSA, 2, 'translating', insn, hex(insn.bytes[0])) def chain_flags_ldimm(st, imm): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 if imm > 0x80: st.expr = Expr(CONST, [1]) else: st.expr = Expr(CONST, [0]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st2) st = st2 if imm: st.expr = Expr(CONST, [0]) else: st.expr = Expr(CONST, [1]) return st def chain_flags_ld(st, reg): op = SSADef.cur(ctx, 'A') st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(COMPARE_GE, [Expr(VAR, [op]), 0x80]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(NOT, [op]) return st def chain_flags_incdec(st, reg): st1 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(NOT, [reg]) st2 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(COMPARE_GE, [reg, 0x80]) return st def chain_flags_bit(st, mem): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(BITFLAGS_N, [SSADef.cur(ctx, 'M', mem)]) st2 = SSAStatement(SSADef(ctx, 'V'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(BITFLAGS_V, [SSADef.cur(ctx, 'M', mem)]) return st def chain_flags_or(st, reg, op): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st = st1 st.expr = Expr(ORFLAGS_N, [reg, op]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st.chain(ctx, st2) st = st2 st.expr = Expr(ORFLAGS_Z, [reg, op]) return st def chain_flags_shl(st, reg, res): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st1.expr = Expr(SHFLAGS_N, [res]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st1.chain(ctx, st2) st2.expr = Expr(NOT, [res]) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN) st2.chain(ctx, st3) st3.expr = Expr(SHLFLAGS_C, [reg]) return st3 def chain_flags_shr(st, reg, res): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN) st.chain(ctx, st1) st1.expr = Expr(SHFLAGS_N, [res]) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN) st1.chain(ctx, st2) st2.expr = Expr(NOT, [res]) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN) st2.chain(ctx, st3) st3.expr = Expr(AND, [reg, 1]) return st3 def chain_flags_and(st, reg, op): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(ANDFLAGS_N, [reg, op])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(ANDFLAGS_Z, [reg, op])) st1.chain(ctx, st2) return st2 def chain_flags_eor(st, reg, op): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(EORFLAGS_N, [reg, op])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(EORFLAGS_Z, [reg, op])) st1.chain(ctx, st2) return st2 def chain_flags_adc(st, reg1, reg2, reg3): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(ADCFLAGS_N, [reg1, reg2, reg3])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(ADCFLAGS_Z, [reg1, reg2, reg3])) st1.chain(ctx, st2) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(ADCFLAGS_C, [reg1, reg2, reg3])) st2.chain(ctx, st3) st4 = SSAStatement(SSADef(ctx, 'V'), ASGN, Expr(ADCFLAGS_V, [reg1, reg2, reg3])) st3.chain(ctx, st4) return st4 def chain_flags_sbb(st, reg1, reg2, reg3): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SBBFLAGS_N, [reg1, reg2, reg3])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(SBBFLAGS_Z, [reg1, reg2, reg3])) st1.chain(ctx, st2) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(SBBFLAGS_C, [reg1, reg2, reg3])) st2.chain(ctx, st3) st4 = SSAStatement(SSADef(ctx, 'V'), ASGN, Expr(SBBFLAGS_V, [reg1, reg2, reg3])) st3.chain(ctx, st4) return st4 def chain_flags_rol(st, reg1, res): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SHFLAGS_N, [res])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(NOT, [res])) st1.chain(ctx, st2) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(SHR, [reg1, 7])) st2.chain(ctx, st3) return st3 def chain_flags_ror(st, reg1, res): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SHFLAGS_N, [res])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(NOT, [res])) st1.chain(ctx, st2) st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(AND, [reg1, 1])) st2.chain(ctx, st3) return st3 def emit_flags_subimm(st, reg, imm): st.dest = [SSADef(ctx, 'C')] st.op = ASGN st.expr = Expr(COMPARE_GE, [SSADef.cur(ctx, reg), imm]) st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(COMPARE_LT, [SSADef.cur(ctx, reg), imm])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(COMPARE_EQ, [SSADef.cur(ctx, reg), imm])) st1.chain(ctx, st2) return st2 # normally, add() will follow the flow of the machine code instructions; # if we know better (such as with branches with constant conditions), we # can put a list of successor instructions here next = None st = SSAStatement() debug(SSA, 2, 'translating', insn, hex(insn.bytes[0]), 'to', st.num) opc = insn.bytes[0] if insn == None: return None st_start = st self.ssa_for_insn[insn] = st st.insn = insn if len(insn.comefrom) > 1: debug(SSA, 3, 'phiing') for g in ctx.local_indices.values(): st.dest = [SSADef(ctx, g.type, g.addr)] st.op = ASGN st.expr = Expr(PHI, [g]) for h in insn.comefrom: if h in self.last_ssa_for_insn: #print('reaching from', self.last_ssa_for_insn[h], [str(x) + '(' + repr(x) + ')' for x in self.last_ssa_for_insn[h].reaching]) for i in self.last_ssa_for_insn[h].reaching: if i.type == g.type and i.addr == g.addr and not i in st.expr.ops: st.expr.ops += [i] st1 = SSAStatement() st.chain(ctx, st1) st = st1 def abs(): return insn.bytes[1] + (insn.bytes[2] << 8) def zp(): return insn.bytes[1] def imm(): return insn.bytes[1] def do_st_abs(reg): if self.is_io(abs()): st.op = IMPURE st.dest = [] st.expr = Expr(IOOUT, [abs(), SSADef.cur(ctx, reg)]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.dest = [SSADef(ctx, 'M', abs())] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, reg)]) def do_ld_abs(reg): nonlocal st st.dest = [SSADef(ctx, reg)] st.op = ASGN if self.is_io(abs()): st.expr = Expr(IOIN, [abs()]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', abs())]) st = chain_flags_ld(st, reg) def do_st_xy(src, addr, reg): st.dest = [] st.op = IMPURE if self.is_io(addr): st.expr = Expr(IOOUT, [Expr(ADD, [addr, SSADef.cur(ctx, reg)]), SSADef.cur(ctx, src)]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.expr = Expr(STORE, [SSADef.cur(ctx, src), addr, SSADef.cur(ctx, reg)]) def do_ld_xy(dst, addr, reg): nonlocal st st.dest = [SSADef(ctx, dst)] st.op = ASGN if self.is_io(addr): st.expr = Expr(IOIN, [Expr(ADD, [addr, SSADef.cur(ctx, reg)])]) st.expr.dont_propagate = True st.expr.dont_eliminate = True else: st.expr = Expr(LOAD, [addr, SSADef.cur(ctx, reg)]) st = chain_flags_ld(st, dst) def do_branch(flag, positive): nonlocal next, st if insn.fake_branch >= 0: next = [insn.next[insn.fake_branch]] st.op = ASGN st.expr = Expr(NOP, [0]) else: st.op = BRANCH_COND st.expr = Expr(VAR if positive else NOT, [SSADef.cur(ctx, flag)]) st.dest = [] if opc == 0x00: # BRK st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['brk', imm()]) elif opc == 0x01: # ORA (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_mem = Expr(LOAD, [addr, 0]) current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(OR, [current_a, current_mem]) st = chain_flags_or(st, current_a, current_mem) elif opc == 0x05: # ORA zp current_a = SSADef.cur(ctx, 'A') st.op = ASGN st.expr = Expr(OR, [current_a, SSADef.cur(ctx, 'M', zp())]) st.dest = [SSADef(ctx, 'A')] st = chain_flags_or(st, current_a, SSADef.cur(ctx, 'M', zp())) elif opc == 0x06: # ASL zp current_mem = SSADef.cur(ctx, 'M', zp()) st.op = ASGN st.expr = Expr(SHL, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', zp())] st = chain_flags_shl(st, current_mem, st.expr) elif opc == 0x08: # PHP st.dest = [SSADef(ctx, 's', sp)] sp -= 1 st.op = ASGN st.expr = Expr(FLAGS, [SSADef.cur(ctx, 'C'),SSADef.cur(ctx, 'Z'),SSADef.cur(ctx, 'N'),SSADef.cur(ctx, 'V')]) elif opc == 0x09: # ORA imm current_a = SSADef.cur(ctx, 'A') st.op = ASGN st.expr = Expr(OR, [current_a, imm()]) st.dest = [SSADef(ctx, 'A')] st = chain_flags_or(st, current_a, imm()) elif opc == 0x0a: # ASL A current_a = SSADef.cur(ctx, 'A') st.op = ASGN st.expr = Expr(SHL, [current_a, 1]) st.dest = [SSADef(ctx, 'A')] st = chain_flags_shl(st, current_a, st.expr) elif opc == 0x0d: # ORA abs current_a = SSADef.cur(ctx, 'A') st.op = ASGN st.expr = Expr(OR, [current_a, SSADef.cur(ctx, 'M', abs())]) st.dest = [SSADef(ctx, 'A')] st = chain_flags_or(st, current_a, SSADef.cur(ctx, 'M', abs())) elif opc == 0x0e: # ASL abs current_mem = SSADef.cur(ctx, 'M', abs()) st.op = ASGN st.expr = Expr(SHL, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', abs())] st = chain_flags_shl(st, current_mem, st.expr) elif opc == 0x10: # BPL dd do_branch('N', False) elif opc == 0x11: # ORA (zp),Y current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')]) st.expr = Expr(OR, [current_a, operand]) st = chain_flags_or(st, current_a, operand) elif opc == 0x15: # ORA zp,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) st.expr = Expr(OR, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_or(st, current_a, current_mem) elif opc == 0x16: # ASL zp,X current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) shlex = Expr(SHL, [current_mem, 1]) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [shlex, zp(), SSADef.cur(ctx, 'X')]) st = chain_flags_shl(st, current_mem, shlex) elif opc == 0x18: # CLC st.dest = [SSADef(ctx, 'C')] st.expr = Expr(CONST, [0]) st.op = ASGN elif opc == 0x19: # ORA abs,Y current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')]) st.expr = Expr(OR, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_or(st, current_a, current_mem) elif opc == 0x1d: # ORA abs,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) st.expr = Expr(OR, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_or(st, current_a, current_mem) elif opc == 0x1e: # ASL abs,X current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) shlex = Expr(SHL, [current_mem, 1]) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [shlex, abs(), SSADef.cur(ctx, 'X')]) st = chain_flags_shl(st, current_mem, shlex) elif opc == 0x20: # JSR abs st.expr = Expr(ARGS, [abs()] + self.fun_args(ctx, insn.next[1], st, sp)) st.dest = self.fun_returns(ctx, insn.next[1], st) st.op = CALL elif opc == 0x21: # AND (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_mem = Expr(LOAD, [addr, 0]) current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(AND, [current_a, current_mem]) st = chain_flags_and(st, current_a, current_mem) elif opc == 0x24: # BIT zp st.expr = Expr(COMPARE_EQ, [Expr(AND, [SSADef.cur(ctx, 'A'), SSADef.cur(ctx, 'M', zp())]), 0]) st.dest = [SSADef(ctx, 'Z')] st.op = ASGN st = chain_flags_bit(st, zp()) elif opc == 0x25: # AND zp current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', zp()) st.expr = Expr(AND, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_and(st, current_a, current_mem) elif opc == 0x26: # ROL zp current_mem = SSADef.cur(ctx, 'M', zp()) current_c = SSADef.cur(ctx, 'C') st.op = ASGN st.expr = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c]) st.expr.dont_propagate = True st.dest = [SSADef(ctx, 'M', zp())] st = chain_flags_rol(st, current_mem, st.expr) elif opc == 0x28: # PLP sp += 1 flags = SSADef.cur(ctx, 's', sp) for i in [('C', DEFLAGS_C), ('Z', DEFLAGS_Z), ('N', DEFLAGS_N), ('V', DEFLAGS_V)]: st.op = ASGN st.dest = [SSADef(ctx, i[0])] st.expr = Expr(i[1], [flags]) if i[0] != 'V': st1 = SSAStatement() st.chain(ctx, st1) st = st1 elif opc == 0x29: # AND imm current_a = SSADef.cur(ctx, 'A') st.op = ASGN st.expr = Expr(AND, [current_a, imm()]) st.dest = [SSADef(ctx, 'A')] st = chain_flags_and(st, current_a, imm()) elif opc == 0x2a: # ROL A current_a = SSADef.cur(ctx, 'A') current_c = SSADef.cur(ctx, 'C') st.op = ASGN st.expr = Expr(OR, [Expr(SHL, [current_a, 1]), current_c]) st.expr.dont_propagate = True st.dest = [SSADef(ctx, 'A')] st = chain_flags_rol(st, current_a, st.expr) elif opc == 0x2c: # BIT abs st.expr = Expr(COMPARE_EQ, [Expr(AND, [SSADef.cur(ctx, 'A'), SSADef.cur(ctx, 'M', abs())]), 0]) st.dest = [SSADef(ctx, 'Z')] st.op = ASGN st = chain_flags_bit(st, abs()) elif opc == 0x2d: # AND abs current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', abs()) st.expr = Expr(AND, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_and(st, current_a, current_mem) elif opc == 0x2e: # ROL abs current_mem = SSADef.cur(ctx, 'M', abs()) current_c = SSADef.cur(ctx, 'C') st.op = ASGN st.expr = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c]) st.expr.dont_propagate = True st.dest = [SSADef(ctx, 'M', abs())] st = chain_flags_rol(st, current_mem, st.expr) elif opc == 0x30: # BMI dd do_branch('N', True) elif opc == 0x31: # AND (zp),Y current_mem = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')]) current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(AND, [current_a, current_mem]) st = chain_flags_and(st, current_a, current_mem) elif opc == 0x35: # AND zp,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) st.expr = Expr(AND, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_and(st, current_a, current_mem) elif opc == 0x36: # ROL zp,X current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_c = SSADef.cur(ctx, 'C') st.op = IMPURE rolex = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c]) rolex.dont_propagate = True st.dest = [] st.expr = Expr(STORE, [rolex, zp(), SSADef.cur(ctx, 'X')]) st = chain_flags_rol(st, current_mem, rolex) elif opc == 0x38: # SEC st.dest = [SSADef(ctx, 'C')] st.op = ASGN st.expr = Expr(CONST, [1]) elif opc == 0x39: # AND abs,Y current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')]) st.expr = Expr(AND, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_and(st, current_a, current_mem) elif opc == 0x3d: # AND abs,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) st.expr = Expr(AND, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_and(st, current_a, current_mem) elif opc == 0x3e: # ROL abs,X current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) current_c = SSADef.cur(ctx, 'C') st.op = IMPURE rolex = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c]) rolex.dont_propagate = True st.dest = [] st.expr = Expr(STORE, [rolex, abs(), SSADef.cur(ctx, 'X')]) st = chain_flags_rol(st, current_mem, rolex) elif opc == 0x40: # RTI st.dest = [] st.op = RETURN st.expr = None st.add_comment('RTI') elif opc == 0x41: # EOR (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_mem = Expr(LOAD, [addr, 0]) current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(EOR, [current_a, current_mem]) st = chain_flags_eor(st, current_a, current_mem) elif opc == 0x45: # EOR zp current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', zp()) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(EOR, [current_a, current_mem]) st = chain_flags_eor(st, current_a, current_mem) elif opc == 0x46: # LSR zp current_mem = SSADef.cur(ctx, 'M', zp()) st.op = ASGN st.expr = Expr(SHR, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', zp())] st = chain_flags_shr(st, current_mem, st.expr) elif opc == 0x48: # PHA st.dest = [SSADef(ctx, 's', sp)] sp -= 1 st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')]) elif opc == 0x49: # EOR imm current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(EOR, [current_a, imm()]) st = chain_flags_eor(st, current_a, imm()) elif opc == 0x4a: # LSR A current_a = SSADef.cur(ctx, 'A') st.op = ASGN st.expr = Expr(SHR, [current_a, 1]) st.dest = [SSADef(ctx, 'A')] st = chain_flags_shr(st, current_a, st.expr) elif opc == 0x4c: # JMP if insn.next[0] == insn: st.op = ENDLESS_LOOP st.expr = None st.dest = [] elif insn.next[0].sym != None: # tail call if insn.next[0] == ctx.graph.first_insn: debug(SSA, 2, 'tail recursion at', insn) # recursion causes us grief with args/rets, so we avoid it if # possible; here, we can just let the jmp run its course st.op = ASGN st.dest = [] st.expr = Expr(NOP, [0]) else: debug(SSA, 2, 'tail call at', insn) st.expr = Expr(ARGS, [abs()] + self.fun_args(ctx, insn.next[0], st, sp)) st.dest = self.fun_returns(ctx, insn.next[0], st) st.op = CALL st1 = SSAStatement() st.chain(ctx, st1) st = st1 st.dest = [] st.op = RETURN st.expr = None next = [] else: st.op = ASGN st.dest = [] st.expr = Expr(NOP, [0]) elif opc == 0x4d: # EOR abs current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', abs()) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(EOR, [current_a, current_mem]) st = chain_flags_eor(st, current_a, current_mem) elif opc == 0x4e: # LSR abs current_mem = SSADef.cur(ctx, 'M', abs()) st.op = ASGN st.expr = Expr(SHR, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', abs())] st = chain_flags_shr(st, current_mem, st.expr) elif opc == 0x50: # BVC do_branch('V', False) elif opc == 0x51: # EOR (zp),Y current_a = SSADef.cur(ctx, 'A') st.dest = [SSADef(ctx, 'A')] st.op = ASGN operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')]) st.expr = Expr(EOR, [current_a, operand]) st = chain_flags_eor(st, current_a, operand) elif opc == 0x55: # EOR zp,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) st.expr = Expr(EOR, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_eor(st, current_a, current_mem) elif opc == 0x56: # LSR zp,X current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) shrex = Expr(SHR, [current_mem, 1]) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [shrex, zp(), SSADef.cur(ctx, 'X')]) st = chain_flags_shr(st, current_mem, shrex) elif opc == 0x58: # CLI st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['cli']) elif opc == 0x59: # EOR abs,Y current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')]) st.expr = Expr(EOR, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_eor(st, current_a, current_mem) elif opc == 0x5d: # EOR abs,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) st.expr = Expr(EOR, [current_a, current_mem]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st = chain_flags_eor(st, current_a, current_mem) elif opc == 0x5e: # LSR abs,X current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) shrex = Expr(SHR, [current_mem, 1]) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [shrex, abs(), SSADef.cur(ctx, 'X')]) st = chain_flags_shr(st, current_mem, shrex) elif opc == 0x60: # RTS st.dest = [] st.op = RETURN st.expr = None elif opc == 0x61: # ADC (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [addr, 0]) current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, current_mem, current_c]) st = chain_flags_adc(st, current_a, current_mem, current_c) elif opc == 0x65: # ADC zp current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', zp()) current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, current_mem, current_c]) st = chain_flags_adc(st, current_a, current_mem, current_c) elif opc == 0x66: # ROR zp current_mem = SSADef.cur(ctx, 'M', zp()) current_c = SSADef.cur(ctx, 'C') st.op = ASGN st.expr = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])]) st.expr.dont_propagate = True st.dest = [SSADef(ctx, 'M', zp())] st = chain_flags_ror(st, current_mem, st.expr) elif opc == 0x68: # PLA st.dest = [SSADef(ctx, 'A')] st.op = ASGN sp += 1 st.expr = Expr(VAR, [SSADef.cur(ctx, 's', sp)]) st = chain_flags_ld(st, 'A') elif opc == 0x69: # ADC imm current_a = SSADef.cur(ctx, 'A') current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, imm(), current_c]) st = chain_flags_adc(st, current_a, imm(), current_c) elif opc == 0x6a: # ROR A current_a = SSADef.cur(ctx, 'A') current_c = SSADef.cur(ctx, 'C') st.op = ASGN st.expr = Expr(OR, [Expr(SHR, [current_a, 1]), Expr(SHL, [current_c, 7])]) st.expr.dont_propagate = True st.dest = [SSADef(ctx, 'A')] st = chain_flags_ror(st, current_a, st.expr) elif opc == 0x6c: # JMP ind st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['jmp', SSADef.cur(ctx, 'M', abs())]) st.add_comment('XXX: indirect jump not implemented yet') elif opc == 0x6d: # ADC abs current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', abs()) current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, current_mem, current_c]) st = chain_flags_adc(st, current_a, current_mem, current_c) elif opc == 0x6e: # ROR abs current_mem = SSADef.cur(ctx, 'M', abs()) current_c = SSADef.cur(ctx, 'C') st.op = ASGN st.expr = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])]) st.expr.dont_propagate = True st.dest = [SSADef(ctx, 'M', abs())] st = chain_flags_ror(st, current_mem, st.expr) elif opc == 0x70: # BVS dd do_branch('V', True) elif opc == 0x71: # ADC (zp),Y current_a = SSADef.cur(ctx, 'A') current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')]) st.expr = Expr(ADD, [current_a, operand, current_c]) st = chain_flags_adc(st, current_a, operand, current_c) elif opc == 0x75: # ADC zp,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, current_mem, current_c]) st = chain_flags_adc(st, current_a, current_mem, current_c) elif opc == 0x76: # ROR zp,X current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_c = SSADef.cur(ctx, 'C') st.op = IMPURE rorex = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])]) rorex.dont_propagate = True st.dest = [] st.expr = Expr(STORE, [rorex, zp(), SSADef.cur(ctx, 'X')]) st = chain_flags_ror(st, current_mem, rorex) elif opc == 0x78: # SEI st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['sei']) elif opc == 0x79: # ADC abs,Y current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')]) current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, current_mem, current_c]) st = chain_flags_adc(st, current_a, current_mem, current_c) elif opc == 0x7d: # ADC abs,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) current_c = SSADef.cur(ctx, 'C') st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(ADD, [current_a, current_mem, current_c]) st = chain_flags_adc(st, current_a, current_mem, current_c) elif opc == 0x7e: # ROR abs,X current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) current_c = SSADef.cur(ctx, 'C') st.op = IMPURE rorex = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])]) rorex.dont_propagate = True st.dest = [] st.expr = Expr(STORE, [rorex, abs(), SSADef.cur(ctx, 'X')]) st = chain_flags_ror(st, current_mem, rorex) elif opc == 0x81: # STA (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) st.op = IMPURE st.dest = [] st.expr = Expr(STORE, [SSADef.cur(ctx, 'A'), addr, 0]) elif opc == 0x84: # STY zp st.dest = [SSADef(ctx, 'M', zp())] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'Y')]) elif opc == 0x85: # STA zp st.dest = [SSADef(ctx, 'M', zp())] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')]) elif opc == 0x86: # STX zp st.dest = [SSADef(ctx, 'M', zp())] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'X')]) elif opc == 0x88: # DEY st.expr = Expr(SUB, [SSADef.cur(ctx, 'Y'), 1]) st.dest = [SSADef(ctx, 'Y')] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'Y')) elif opc == 0x8a: # TXA st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'X')]) st = chain_flags_ld(st, 'A') elif opc == 0x8c: # STY abs do_st_abs('Y') elif opc == 0x8d: # STA abs do_st_abs('A') elif opc == 0x8e: # STX abs do_st_abs('X') elif opc == 0x90: # BCC dd do_branch('C', False) elif opc == 0x91: # STA (zp),Y current_ind = SSADef.cur(ctx, 'M', zp()) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [SSADef.cur(ctx, 'A'), current_ind, SSADef.cur(ctx, 'Y')]) elif opc == 0x94: # STY zp,X do_st_xy('Y', zp(), 'X') elif opc == 0x95: # STA zp,X do_st_xy('A', zp(), 'X') elif opc == 0x96: # STX zp,Y do_st_xy('X', zp(), 'Y') elif opc == 0x98: # TYA st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'Y')]) st = chain_flags_ld(st, 'A') elif opc == 0x99: # STA abs,Y do_st_xy('A', abs(), 'Y') elif opc == 0x9a: # TXS st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['setsp', SSADef.cur(ctx, 'X')]) elif opc == 0x9d: # STA abs,X do_st_xy('A', abs(), 'X') elif opc == 0xa0: # LDY imm st.dest = [SSADef(ctx, 'Y')] st.op = ASGN st.expr = Expr(CONST, [imm()]) st = chain_flags_ldimm(st, imm()) elif opc == 0xa1: # LDA (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(VAR, [Expr(LOAD, [addr, 0])]) st = chain_flags_ld(st, 'A') elif opc == 0xa2: # LDX imm st.dest = [SSADef(ctx, 'X')] st.op = ASGN st.expr = Expr(CONST, [imm()]) st = chain_flags_ldimm(st, imm()) elif opc == 0xa4: # LDY zp st.dest = [SSADef(ctx, 'Y')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', zp())]) st = chain_flags_ld(st, 'Y') elif opc == 0xa5: # LDA zp st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', zp())]) st = chain_flags_ld(st, 'A') elif opc == 0xa6: # LDX zp st.dest = [SSADef(ctx, 'X')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', zp())]) st = chain_flags_ld(st, 'X') elif opc == 0xa8: # TAY st.dest = [SSADef(ctx, 'Y')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')]) st = chain_flags_ld(st, 'Y') elif opc == 0xa9: # LDA imm st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(CONST, [imm()]) st = chain_flags_ldimm(st, imm()) elif opc == 0xaa: # TAX st.dest = [SSADef(ctx, 'X')] st.op = ASGN st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')]) st = chain_flags_ld(st, 'X') elif opc == 0xac: # LDY abs do_ld_abs('Y') elif opc == 0xad: # LDA abs do_ld_abs('A') elif opc == 0xae: # LDX abs do_ld_abs('X') elif opc == 0xb0: # BCS dd do_branch('C', True) elif opc == 0xb1: # LDA (zp),Y current_ind = SSADef.cur(ctx, 'M', zp()) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(LOAD, [current_ind, SSADef.cur(ctx, 'Y')]) st = chain_flags_ld(st, 'A') elif opc == 0xb4: # LDY zp,X do_ld_xy('Y', zp(), 'X') elif opc == 0xb5: # LDA zp,X do_ld_xy('A', zp(), 'X') elif opc == 0xb6: # LDX zp,Y do_ld_xy('X', zp(), 'Y') elif opc == 0xb8: # CLV st.op = ASGN st.dest = [SSADef(ctx, 'V')] st.expr = Expr(CONST, [0]) elif opc == 0xb9: # LDA abs,Y do_ld_xy('A', abs(), 'Y') elif opc == 0xba: # TSX st.dest = [SSADef(ctx, 'X')] st.op = ASGN st.expr = Expr(INTRINSIC, ['getsp']) elif opc == 0xbc: # LDY abs,X do_ld_xy('Y', abs(), 'X') elif opc == 0xbd: # LDA abs,X do_ld_xy('A', abs(), 'X') elif opc == 0xbe: # LDX abs,Y do_ld_xy('X', abs(), 'Y') elif opc == 0xc0: # CPY imm st = emit_flags_subimm(st, 'Y', imm()) elif opc == 0xc1: # CMP (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) st = emit_flags_subimm(st, 'A', Expr(LOAD, [addr, 0])) elif opc == 0xc4: # CPY zp st = emit_flags_subimm(st, 'Y', SSADef.cur(ctx, 'M', zp())) elif opc == 0xc5: # CMP zp st = emit_flags_subimm(st, 'A', SSADef.cur(ctx, 'M', zp())) elif opc == 0xc6: # DEC zp current_mem = SSADef.cur(ctx, 'M', zp()) st.expr = Expr(SUB, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', zp())] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', zp())) elif opc == 0xc8: # INY st.expr = Expr(ADD, [SSADef.cur(ctx, 'Y'), 1]) st.dest = [SSADef(ctx, 'Y')] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'Y')) elif opc == 0xc9: # CMP imm st = emit_flags_subimm(st, 'A', imm()) elif opc == 0xca: # DEX current_x = SSADef.cur(ctx, 'X') st.expr = Expr(SUB, [current_x, 1]) st.dest = [SSADef(ctx, 'X')] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'X')) elif opc == 0xcc: # CPY abs st = emit_flags_subimm(st, 'Y', SSADef.cur(ctx, 'M', abs())) elif opc == 0xcd: # CMP abs st = emit_flags_subimm(st, 'A', SSADef.cur(ctx, 'M', abs())) elif opc == 0xce: # DEC abs current_mem = SSADef.cur(ctx, 'M', abs()) st.expr = Expr(SUB, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', abs())] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', abs())) elif opc == 0xd0: # BNE dd do_branch('Z', False) elif opc == 0xd1: # CMP (zp),Y operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')]) st = emit_flags_subimm(st, 'A', operand) elif opc == 0xd5: # CMP zp,X st = emit_flags_subimm(st, 'A', Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])) elif opc == 0xd6: # DEC zp,X current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) subex = Expr(SUB, [current_mem, 1]) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [subex, zp(), SSADef.cur(ctx, 'X')]) st = chain_flags_incdec(st, subex) elif opc == 0xd8: # CLD st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['cld']) st.add_comment('XXX: CLD unimplemented') elif opc == 0xd9: # CMP abs,Y st = emit_flags_subimm(st, 'A', Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')])) elif opc == 0xdd: # CMP abs,X st = emit_flags_subimm(st, 'A', Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])) elif opc == 0xde: # DEC abs,X current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) subex = Expr(SUB, [current_mem, 1]) st.dest = [] st.op = IMPURE st.expr = Expr(STORE, [subex, abs(), SSADef.cur(ctx, 'X')]) st = chain_flags_incdec(st, subex) elif opc == 0xe0: # CPX imm st = emit_flags_subimm(st, 'X', imm()) elif opc == 0xe1: # SBC (zp,X) addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [addr, 0]) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xe4: # CPX zp st = emit_flags_subimm(st, 'X', SSADef.cur(ctx, 'M', zp())) elif opc == 0xe5: # SBC zp current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', zp()) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xe6: # INC zp current_mem = SSADef.cur(ctx, 'M', zp()) st.expr = Expr(ADD, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', zp())] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', zp())) elif opc == 0xe8: # INX current_x = SSADef.cur(ctx, 'X') st.expr = Expr(ADD, [current_x, 1]) st.dest = [SSADef(ctx, 'X')] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'X')) elif opc == 0xe9: # SBC imm current_a = SSADef.cur(ctx, 'A') current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, imm(), current_borrow]) st = chain_flags_sbb(st, current_a, imm(), current_borrow) elif opc == 0xea: # NOP st.op = ASGN st.dest = [] st.expr = Expr(NOP, [0]) elif opc == 0xec: # CPX abs st = emit_flags_subimm(st, 'X', SSADef.cur(ctx, 'M', abs())) elif opc == 0xed: # SBC abs current_a = SSADef.cur(ctx, 'A') current_mem = SSADef.cur(ctx, 'M', abs()) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xee: # INC abs current_mem = SSADef.cur(ctx, 'M', abs()) st.expr = Expr(ADD, [current_mem, 1]) st.dest = [SSADef(ctx, 'M', abs())] st.op = ASGN st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', abs())) elif opc == 0xf0: # BEQ dd do_branch('Z', True) elif opc == 0xf1: # SBC (zp),Y current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')]) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xf5: # SBC zp,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xf6: # INC zp,X current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]) result = Expr(ADD, [current_mem, 1]) st.expr = Expr(STORE, [result, zp(), SSADef.cur(ctx, 'X')]) st.dest = [] st.op = IMPURE st = chain_flags_incdec(st, result) elif opc == 0xf8: # SED st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['sed']) st.add_comment('XXX: SED unimplemented') elif opc == 0xf9: # SBC abs,Y current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')]) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xfd: # SBC abs,X current_a = SSADef.cur(ctx, 'A') current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')]) st.dest = [SSADef(ctx, 'A')] st.op = ASGN st.expr = Expr(SUB, [current_a, current_mem, current_borrow]) st = chain_flags_sbb(st, current_a, current_mem, current_borrow) elif opc == 0xfe: # INC abs,X current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]) result = Expr(ADD, [current_mem, 1]) st.expr = Expr(STORE, [result, abs(), SSADef.cur(ctx, 'X')]) st.dest = [] st.op = IMPURE st = chain_flags_incdec(st, result) elif opc == OPC_OUTOFRANGE: st.dest = [] st.op = IMPURE st.expr = Expr(INTRINSIC, ['thunk', insn.addr]) elif opc in [ 0x02, 0x03, 0x04, 0x07, 0x0b, 0x0c, 0x0f, 0x12, 0x13, 0x14, 0x17, 0x1a, 0x1b, 0x1c, 0x1f, 0x22, 0x23, 0x27, 0x2b, 0x2f, 0x32, 0x33, 0x34, 0x37, 0x3a, 0x3b, 0x3c, 0x3f, 0x42, 0x43, 0x44, 0x47, 0x4b, 0x4f, 0x52, 0x53, 0x54, 0x57, 0x5a, 0x5b, 0x5c, 0x5f, 0x62, 0x63, 0x64, 0x67, 0x6b, 0x6f, 0x72, 0x73, 0x74, 0x77, 0x7a, 0x7b, 0x7c, 0x7f, 0x80, 0x82, 0x83, 0x87, 0x89, 0x8b, 0x8f, 0x92, 0x93, 0x97, 0x9b, 0x9c, 0x9e, 0x9f, 0xa3, 0xa7, 0xab, 0xaf, 0xb2, 0xb3, 0xb7, 0xbb, 0xbf, 0xc2, 0xc3, 0xc7, 0xcb, 0xcf, 0xd2, 0xd3, 0xd4, 0xd7, 0xda, 0xdb, 0xdc, 0xdf, 0xe2, 0xe3, 0xe7, 0xeb, 0xef, 0xf2, 0xf3, 0xf4, 0xf7, 0xfa, 0xfb, 0xfc, 0xff]: # illegal opcode # XXX: add switch to allow 'useful' illegal opcodes st.op = IMPURE st.expr = Expr(INTRINSIC, ['illegal', opc]) st.dest = [] st.add_comment('XXX: unimplemented illegal opcode') else: raise InternalError('unknown opcode ' + hex(opc)) # all current indices are reaching, with the exception of anything # below the stack pointer st.reaching = [] for i in ctx.local_indices.values(): if i.type != 's':# or i.addr > sp: st.reaching += [i] self.last_ssa_for_insn[insn] = st return (st_start, st, sp, bp, end_bp, next)
def chain_flags_eor(st, reg, op): st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(EORFLAGS_N, [reg, op])) st.chain(ctx, st1) st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(EORFLAGS_Z, [reg, op])) st1.chain(ctx, st2) return st2