Ejemplo n.º 1
0
        BlockEncoder(int bitness, InstructionBlock[] instrBlocks, BlockEncoderOptions options)
        {
            if (bitness != 16 && bitness != 32 && bitness != 64)
            {
                throw new ArgumentOutOfRangeException(nameof(bitness));
            }
            if (instrBlocks == null)
            {
                throw new ArgumentNullException(nameof(instrBlocks));
            }
            this.bitness = bitness;
            nullEncoder  = Encoder.Create(bitness, NullCodeWriter.Instance);
            this.options = options;

            blocks = new Block[instrBlocks.Length];
            int instrCount = 0;

            for (int i = 0; i < instrBlocks.Length; i++)
            {
                var instructions = instrBlocks[i].Instructions;
                if (instructions == null)
                {
                    throw new ArgumentException();
                }
                var   instrs = new Instr[instructions.Count];
                ulong ip     = instrBlocks[i].RIP;
                for (int j = 0; j < instrs.Length; j++)
                {
                    var instruction = instructions[j];
                    var instr       = Instr.Create(this, ref instruction);
                    instr.IP  = ip;
                    instrs[j] = instr;
                    instrCount++;
                    ip += instr.Size;
                }
                blocks[i] = new Block(this, instrBlocks[i].CodeWriter, instrBlocks[i].RIP, instrBlocks[i].RelocInfos, instrBlocks[i].NewInstructionOffsets, instrBlocks[i].ConstantOffsets, instrs);
            }
            // Optimize from low to high addresses
            Array.Sort(blocks, (a, b) => a.RIP.CompareTo(b.RIP));

            // There must not be any instructions with the same IP, except if IP = 0 (default value)
            var toInstr = new Dictionary <ulong, Instr>(instrCount);

            this.toInstr = toInstr;
            bool hasMultipleZeroIPInstrs = false;

            foreach (var block in blocks)
            {
                foreach (var instr in block.Instructions)
                {
                    ulong origIP = instr.OrigIP;
                    if (toInstr.TryGetValue(origIP, out var origInstr))
                    {
                        if (origIP != 0)
                        {
                            throw new ArgumentException($"Multiple instructions with the same IP: 0x{origIP:X}");
                        }
                        hasMultipleZeroIPInstrs = true;
                    }
                    else
                    {
                        toInstr[origIP] = instr;
                    }
                }
            }
            if (hasMultipleZeroIPInstrs)
            {
                toInstr.Remove(0);
            }

            foreach (var block in blocks)
            {
                ulong ip = block.RIP;
                foreach (var instr in block.Instructions)
                {
                    instr.IP = ip;
                    var oldSize = instr.Size;
                    instr.Initialize();
                    if (instr.Size > oldSize)
                    {
                        throw new InvalidOperationException();
                    }
                    ip += instr.Size;
                }
            }
        }