Пример #1
0
        public override void WriteTo(FlashWriter output)
        {
            var marks            = new Dictionary <ASInstruction, long>();
            var sharedExits      = new Dictionary <ASInstruction, List <ASInstruction> >();
            var forwardCaseExits = new Dictionary <ASInstruction, Tuple <LookUpSwitchIns, int> >();

            foreach (ASInstruction instruction in _instructions)
            {
                long previousPosition = output.Position;
                marks.Add(instruction, previousPosition);
                instruction.WriteTo(output);

                List <ASInstruction> jumpers = null;
                if (sharedExits.TryGetValue(instruction, out jumpers))
                {
                    foreach (ASInstruction jumper in jumpers)
                    {
                        long position    = marks[jumper];
                        var  fixedOffset = (uint)(previousPosition - (position + 4));

                        ((Jumper)jumper).Offset = fixedOffset;
                        Rewrite(output, jumper, position);
                    }
                    sharedExits.Remove(instruction);
                }

                Tuple <LookUpSwitchIns, int> switchIdentity = null;
                if (forwardCaseExits.TryGetValue(instruction, out switchIdentity))
                {
                    int             caseIndex    = switchIdentity.Item2;
                    LookUpSwitchIns lookUpSwitch = switchIdentity.Item1;

                    long position    = marks[lookUpSwitch];
                    var  fixedOffset = (uint)(previousPosition - position);

                    if (caseIndex == lookUpSwitch.CaseOffsets.Count)
                    {
                        lookUpSwitch.DefaultOffset = fixedOffset;
                    }
                    else
                    {
                        lookUpSwitch.CaseOffsets[caseIndex] = fixedOffset;
                    }
                    Rewrite(output, lookUpSwitch, position);
                }

                if (instruction.OP == OPCode.LookUpSwitch)
                {
                    bool            requiresRewrite = false;
                    var             lookUpSwitch    = (LookUpSwitchIns)instruction;
                    ASInstruction[] cases           = SwitchExits[lookUpSwitch];
                    for (int i = 0; i < cases.Length; i++)
                    {
                        ASInstruction exit = cases[i];
                        if (exit.OP != OPCode.Label)
                        {
                            forwardCaseExits.Add(exit, Tuple.Create(lookUpSwitch, i));
                        }
                        else
                        {
                            requiresRewrite = true;
                            long exitPosition = marks[exit];
                            long jumpCount    = (previousPosition - (exitPosition + 1));

                            uint fixedOffset = (uint)(uint.MaxValue - jumpCount);
                            if (i == (cases.Length - 1))
                            {
                                lookUpSwitch.DefaultOffset = fixedOffset;
                            }
                            else
                            {
                                lookUpSwitch.CaseOffsets[i] = fixedOffset;
                            }
                        }
                    }
                    if (requiresRewrite)
                    {
                        Rewrite(output, lookUpSwitch, previousPosition);
                    }
                }
                else if (Jumper.IsValid(instruction.OP))
                {
                    var jumper = (Jumper)instruction;
                    if (jumper.Offset == 0)
                    {
                        continue;
                    }

                    ASInstruction exit = null;
                    if (!JumpExits.TryGetValue(jumper, out exit))
                    {
                        // An exit for this jump instruction could not be found, perhaps its' offset exceeds the index limit?
                        continue;
                    }
                    else if (exit.OP != OPCode.Label || !marks.ContainsKey(exit)) // Forward jumps can have a label for an exit, as long as it is located ahead.
                    {
                        jumpers = null;
                        if (!sharedExits.TryGetValue(exit, out jumpers))
                        {
                            jumpers = new List <ASInstruction>();
                            sharedExits.Add(exit, jumpers);
                        }
                        jumpers.Add(jumper);
                    }
                    else // Backward jumps must always have a label for an exit, and must be behind this instruction.
                    {
                        long exitPosition = marks[exit];
                        long jumpCount    = (output.Position - (exitPosition + 1));

                        var fixedOffset = (uint)(uint.MaxValue - jumpCount);
                        jumper.Offset = fixedOffset;

                        Rewrite(output, jumper, previousPosition);
                    }
                }
            }
        }
Пример #2
0
        private void LoadInstructions()
        {
            var caseIndices      = new Dictionary <long, int>();
            var marks            = new Dictionary <long, ASInstruction>();
            var sharedExits      = new Dictionary <long, List <Jumper> >();
            var forwardCaseExits = new Dictionary <long, LookUpSwitchIns>();

            using (var input = new FlashReader(_body.Code))
            {
                while (input.IsDataAvailable)
                {
                    long previousPosition = input.Position;
                    var  instruction      = ASInstruction.Create(_abc, input);
                    marks[previousPosition] = instruction;

                    _indices.Add(instruction, _indices.Count);
                    _instructions.Add(instruction);

                    List <ASInstruction> instructions = null;
                    if (!_opGroups.TryGetValue(instruction.OP, out instructions))
                    {
                        instructions = new List <ASInstruction>();
                        _opGroups.Add(instruction.OP, instructions);
                    }
                    instructions.Add(instruction);

                    List <Jumper> jumpers = null;
                    if (sharedExits.TryGetValue(previousPosition, out jumpers))
                    {
                        // This is an exit position for a jump instruction, or more.
                        foreach (Jumper jumper in jumpers)
                        {
                            JumpExits.Add(jumper, instruction);
                        }
                        sharedExits.Remove(previousPosition);
                    }

                    LookUpSwitchIns lookUpSwitch = null;
                    if (forwardCaseExits.TryGetValue(previousPosition, out lookUpSwitch))
                    {
                        int index = caseIndices[previousPosition];
                        SwitchExits[lookUpSwitch][index] = instruction;

                        caseIndices.Remove(previousPosition);
                        forwardCaseExits.Remove(previousPosition);
                    }

                    if (instruction.OP == OPCode.LookUpSwitch)
                    {
                        lookUpSwitch = (LookUpSwitchIns)instruction;
                        var offsets = new List <uint>(lookUpSwitch.CaseOffsets);
                        offsets.Add(lookUpSwitch.DefaultOffset);

                        var cases = new ASInstruction[offsets.Count];
                        for (int i = 0; i < offsets.Count; i++)
                        {
                            ASInstruction exit         = null;
                            long          exitPosition = (previousPosition + offsets[i]);
                            if (exitPosition <= input.Length)
                            {
                                caseIndices.Add(exitPosition, i);
                                forwardCaseExits.Add(exitPosition, lookUpSwitch);
                            }
                            else
                            {
                                cases[i] = exit;
                                exit     = marks[(exitPosition - uint.MaxValue) - 1];
                            }
                        }
                        SwitchExits.Add(lookUpSwitch, cases);
                    }
                    else if (Jumper.IsValid(instruction.OP))
                    {
                        var jumper = (Jumper)instruction;
                        if (jumper.Offset == 0)
                        {
                            continue;
                        }

                        long exitPosition = (input.Position + jumper.Offset);
                        if (exitPosition == input.Length)
                        {
                            // Jump exit does not exist at this (non-existent)index, do not look for exit.
                            continue;
                        }
                        else if (exitPosition < input.Length) // Forward jump.
                        {
                            jumpers = null;
                            if (!sharedExits.TryGetValue(exitPosition, out jumpers))
                            {
                                jumpers = new List <Jumper>();
                                sharedExits.Add(exitPosition, jumpers);
                            }
                            jumpers.Add(jumper);
                        }
                        else // Backwards jump.
                        {
                            var label = (LabelIns)marks[(exitPosition - uint.MaxValue) - 1];
                            JumpExits.Add(jumper, label);
                        }
                    }
                }
            }
        }