Example #1
0
def _establish_warps(state, instructions):
    state.blocks[0].warpins_count = 1

    enumerated_blocks = enumerate(state.blocks[:-1])
    for i, block in enumerated_blocks:
        if state.blocks.__contains__(block) is None:
            continue

        state.block = block

        end_addr = block.last_address + 1
        start_addr = max(block.last_address - 1, block.first_address)

        # Catch certain double unconditional jumps caused by logical primitives in expressions:
        if start_addr == (end_addr - 1) \
                and end_addr + 1 < len(instructions) \
                and instructions[start_addr].opcode == ins.JMP.opcode \
                and instructions[end_addr].opcode == ins.JMP.opcode \
                and instructions[start_addr].A == instructions[end_addr].A \
                and instructions[start_addr].CD == 0:

            end_instruction_destination = end_addr + instructions[
                end_addr].CD + 1
            target_instruction_A = instructions[start_addr].A
            exit_instruction_found = False

            # When two consecutive jumps are found with the same A operand, lookahead for the end jump.
            following_destination = -1
            for j in range(end_addr + 1, len(instructions) - 1):
                following_instruction = instructions[j]
                if following_instruction.opcode == ins.JMP.opcode:
                    if following_instruction.A == target_instruction_A:
                        following_destination = get_jump_destination(
                            j, following_instruction)
                        exit_instruction_found = True
                        break

            # If we find the exit jump and we're not skipping it (if true then break else),
            #  form the original two jumps into a fake conditional warp.
            if exit_instruction_found \
                    and end_instruction_destination <= following_destination:
                fixed_instruction = ins.ISF()
                fixed_instruction.CD = ins.SLOT_FALSE

                instructions[start_addr] = fixed_instruction
                state.blocks.pop(state.blocks.index(block) + 1)

                block.last_address += 1
                start_addr = max(block.last_address - 1, block.first_address)
                end_addr = block.last_address + 1

        warp = instructions[start_addr:end_addr]

        block.warp, shift = _build_warp(state, block.last_address, warp)

        setattr(block, "_last_body_addr", block.last_address - shift)
        setattr(block.warp, "_addr", block.last_address - shift + 1)

    last_block = state.blocks[-1]
    last_block.warp = nodes.EndWarp()

    setattr(last_block, "_last_body_addr", last_block.last_address)
    setattr(last_block.warp, "_addr", last_block.last_address)
Example #2
0
def _fix_broken_repeat_until_loops(state, instructions):
    enumerated_instructions = enumerate(instructions)
    for i, instruction in enumerated_instructions:

        if instruction.opcode == ins.LOOP.opcode:

            # Check for the conditional jump that restarts the loop
            loop_exit_addr = get_jump_destination(i, instruction)
            loop_condition_addr = loop_exit_addr - 1
            loop_condition_instruction = instructions[loop_condition_addr]
            if not loop_condition_instruction.opcode == ins.JMP.opcode:
                if get_jump_destination(loop_condition_addr,
                                        loop_condition_instruction) <= i:
                    continue

                # It's not there, so this is probably a repeat-until true loop.

                # We need a fake conditional warp that is treated as 'true' by the writer
                fixed_cond_instruction = ins.ISF()
                fixed_cond_instruction.CD = ins.SLOT_TRUE

                # Resulting jump to the loop starting point
                fixed_jump_instruction = ins.JMP()
                fixed_jump_instruction.CD = i - loop_condition_addr - 1

                # Add fake conditional instructions
                insertion_index = loop_condition_addr + 1
                _insert_instruction(state, instructions, insertion_index,
                                    fixed_jump_instruction)
                _insert_instruction(state, instructions, insertion_index,
                                    fixed_cond_instruction)

                shift = 2

                # Fix non-break destinations within the loop
                # Breaks in the empty-condition loop point towards the same exit destination
                # as non-breaks, so we'll have to search for a pattern of jumps.

                leading_jump = False
                start_index = i + 1
                for j in range(start_index, insertion_index):
                    checked_instruction = instructions[j]

                    # Look for following JMP instructions
                    if checked_instruction.opcode == ins.JMP.opcode:

                        # Leading jump indicates this is a break?
                        if not leading_jump:
                            checked_instruction_destination \
                                = get_jump_destination(j, checked_instruction)

                            # If the destination would've been moved
                            if checked_instruction.CD >= shift \
                                    and checked_instruction_destination == insertion_index + shift:

                                # Check for an inverted jump pair
                                next_index = j + 1
                                following_instruction = instructions[
                                    next_index]
                                if following_instruction.opcode == ins.JMP.opcode:
                                    following_destination \
                                        = get_jump_destination(next_index, following_instruction)

                                    # e.g. goto 277 followed directly by goto 176
                                    if following_destination < checked_instruction_destination:
                                        leading_jump = True
                                        continue

                                    # e.g. goto 277 followed directly by goto 277
                                    elif following_destination == checked_instruction_destination:
                                        leading_jump = False
                                        continue

                                # Check for else-break-end following this jump
                                following_else_break_found = False
                                prev_jump = False
                                for k in range(next_index, insertion_index):
                                    following_instruction = instructions[k]
                                    if following_instruction.opcode == ins.JMP.opcode:
                                        if not prev_jump:
                                            prev_jump = True

                                        else:
                                            following_destination \
                                                = get_jump_destination(k, following_instruction)

                                            # Don't adjust the checked jump, it's probably a break
                                            if following_instruction.CD >= shift \
                                                    and following_destination \
                                                    == checked_instruction_destination:
                                                following_else_break_found = True
                                                break

                                            prev_jump = False

                                    else:
                                        if prev_jump:
                                            last_destination \
                                                = get_jump_destination(k - 1, instructions[k - 1])
                                            # We can adjust, it's probably not a break
                                            if last_destination < checked_instruction_destination:
                                                break
                                        prev_jump = False

                                if not following_else_break_found:
                                    checked_instruction.CD -= shift
                        leading_jump = True

                    else:
                        leading_jump = False