def _create_next_block(original): block = nodes.Block() block.first_address = original.last_address + 1 block.last_address = block.first_address block.index = original.index + 1 block.warpins_count = original.warpins_count return block
def _blockenize(state, instructions): # Fix inverted comparison expressions (e.g. 0 < variable): _fix_inverted_comparison_expressions(state, instructions) # Fix "repeat until true" encapsulated by another loop _fix_broken_repeat_until_loops(state, instructions) # Fix "var_1 = var_1 [comparison] var_2 and (operation) var_1 or var_1" edge case _fix_broken_unary_expressions(state, instructions) addr = 1 # Duplicates are possible and ok, but we need to sort them out last_addresses = set() while addr < len(instructions): instruction = instructions[addr] opcode = instruction.opcode if opcode not in _WARP_INSTRUCTIONS: addr += 1 continue if opcode in _JUMP_WARP_INSTRUCTIONS: destination = get_jump_destination(addr, instruction) if opcode != ins.UCLO.opcode or destination != addr + 1: last_addresses.add(destination - 1) last_addresses.add(addr) else: last_addresses.add(addr) addr += 1 last_addresses = sorted(list(last_addresses)) last_addresses.append(len(instructions) - 1) # This could happen if something jumps to the first instruction # We don't need "zero block" with function header, so simply ignore # this if last_addresses[0] == 0: last_addresses.pop(0) previous_last_address = 0 index = 0 for last_address in last_addresses: block = nodes.Block() block.index = index block.first_address = previous_last_address + 1 block.last_address = last_address state.blocks.append(block) state.block_starts[block.first_address] = block previous_last_address = last_address index += 1
def _build_conditional_warp(state, last_addr, instructions): condition = instructions[-2] condition_addr = last_addr - 1 warp = nodes.ConditionalWarp() if condition.opcode in (ins.ISTC.opcode, ins.ISFC.opcode): expression = _build_unary_expression(state, condition_addr, condition) setattr(warp, "_slot", condition.A) elif condition.opcode >= ins.IST.opcode: expression = _build_unary_expression(state, condition_addr, condition) setattr(warp, "_slot", condition.CD) else: expression = _build_comparison_expression(state, condition_addr, condition) warp.condition = expression jump = instructions[-1] jump_addr = last_addr destination = get_jump_destination(jump_addr, jump) # A condition is inverted during the preparation phase above warp.false_target = state._warp_in_block(destination) warp.true_target = state._warp_in_block(jump_addr + 1) shift = 2 if destination == (jump_addr + 1) \ and condition.opcode not in (ins.ISTC.opcode, ins.ISFC.opcode): # This is an empty 'then' or 'else'. The simplest way to handle it is # to insert a Block containing just a no-op statement. block = nodes.Block() block.first_address = jump_addr + 1 block.last_address = block.first_address block.index = warp.true_target.index block.warpins_count = 1 setattr(block, "_last_body_addr", block.last_address - shift) block.warp = nodes.UnconditionalWarp() block.warp.type = nodes.UnconditionalWarp.T_FLOW block.warp.target = warp.true_target setattr(block.warp, "_addr", block.last_address - shift + 1) state.blocks.insert(state.blocks.index(warp.true_target), block) warp.true_target = block _create_no_op(state, jump_addr, block) return warp, shift
def _blockenize(state, instructions): "将指令划分成代码块" addr = 1 # Duplicates are possible and ok, but we need to sort them out last_addresses = set() while addr < len(instructions): instruction = instructions[addr] opcode = instruction.opcode if opcode not in _WARP_INSTRUCTIONS: addr += 1 continue if opcode in _JUMP_WARP_INSTRUCTIONS: # 跳转:当前指令地址,及跳转目的地的前一地址为一个代码块的末端 destination = get_jump_destination(addr, instruction) if opcode != ins.UCLO.opcode or destination != addr + 1: last_addresses.add(destination - 1) last_addresses.add(addr) else: last_addresses.add(addr) addr += 1 last_addresses = sorted(list(last_addresses)) last_addresses.append(len(instructions) - 1) # This could happen if something jumps to the first instruction # We don't need "zero block" with function header, so simply ignore # this if last_addresses[0] == 0: last_addresses.pop(0) previous_last_address = 0 index = 0 for last_address in last_addresses: block = nodes.Block() block.index = index block.first_address = previous_last_address + 1 block.last_address = last_address state.blocks.append(block) state.block_starts[block.first_address] = block previous_last_address = last_address index += 1
def _unwarp_loops(blocks, repeat_until): loops = _find_all_loops(blocks, repeat_until) if len(loops) == 0: return blocks fixed = _cleanup_breaks_and_if_ends(loops, blocks) for start, end in fixed: start_index = blocks.index(start) end_index = blocks.index(end) if repeat_until: body = blocks[start_index:end_index] else: body = blocks[start_index + 1:end_index] loop = _unwarp_loop(start, end, body) body = loop.statements.contents block = nodes.Block() block.first_address = body[0].first_address block.last_address = body[-1].last_address block.index = start.index + 1 block.contents.append(loop) block.warp = nodes.UnconditionalWarp() block.warp.type = nodes.UnconditionalWarp.T_FLOW block.warp.target = end _replace_targets(blocks, body[0], block) _set_end(body[-1]) _unwarp_breaks(start, body, end) blocks = blocks[:start_index + 1] + [block] + blocks[end_index:] return blocks