Esempio n. 1
0
        public static int GetEncodedSize(this Instruction Instruction, int bitness, ulong IP = 0)
        {
            var Writer   = new MemoryCodeWriter();
            var Compiler = Encoder.Create(bitness, Writer);

            return((int)Compiler.Encode(Instruction, (ulong)Writer.Count + IP));
        }
Esempio n. 2
0
        public static uint Encode(this Encoder Encoder, InstructionList List, ulong IP)
        {
            uint Len = 0;

            foreach (var Instruction in List)
            {
                Len += Encoder.Encode(Instruction, IP + Len);
            }
            return(Len);
        }
Esempio n. 3
0
        public static int GetEncodedSize(this InstructionList List, int bitness, ulong IP = 0)
        {
            var Writer   = new MemoryCodeWriter();
            var Compiler = Encoder.Create(bitness, Writer);

            foreach (var Instruction in List)
            {
                Compiler.Encode(Instruction, (ulong)Writer.Count + IP);
            }

            return(Writer.Count);
        }
Esempio n. 4
0
        BlockEncoder(int bitness, InstructionBlock[] instrBlocks, BlockEncoderOptions options)
        {
            if (bitness != 16 && bitness != 32 && bitness != 64)
            {
                throw new ArgumentOutOfRangeException(nameof(bitness));
            }
            if (instrBlocks is 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 is null)
                {
                    throw new ArgumentException();
                }
                var block = new Block(this, instrBlocks[i].CodeWriter, instrBlocks[i].RIP, ReturnRelocInfos ? new List <RelocInfo>() : null);
                blocks[i] = block;
                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, block, instruction);
                    instr.IP  = ip;
                    instrs[j] = instr;
                    instrCount++;
                    Debug.Assert(instr.Size != 0);
                    ip += instr.Size;
                }
                block.SetInstructions(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 _))
                    {
                        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(this);
                    if (instr.Size > oldSize)
                    {
                        throw new InvalidOperationException();
                    }
                    ip += instr.Size;
                }
            }
        }
Esempio n. 5
0
        bool Encode(out string errorMessage)
        {
            const int MAX_ITERS = 1000;

            for (int iter = 0; iter < MAX_ITERS; iter++)
            {
                bool updated = false;
                foreach (var block in blocks)
                {
                    ulong ip = block.RIP;
                    foreach (var instr in block.Instructions)
                    {
                        instr.IP = ip;
                        var oldSize = instr.Size;
                        if (instr.Optimize())
                        {
                            if (instr.Size > oldSize)
                            {
                                errorMessage = "Internal error: new size > old size";
                                return(false);
                            }
                            if (instr.Size < oldSize)
                            {
                                updated = true;
                            }
                        }
                        else if (instr.Size != oldSize)
                        {
                            errorMessage = "Internal error: new size != old size";
                            return(false);
                        }
                        ip += instr.Size;
                    }
                }
                if (!updated)
                {
                    break;
                }
            }

            foreach (var block in blocks)
            {
                block.InitializeData();
            }

            foreach (var block in blocks)
            {
                var   encoder = Encoder.Create(bitness, block.CodeWriter);
                ulong ip      = block.RIP;
                var   newInstructionOffsets = block.NewInstructionOffsets;
                var   constantOffsets       = block.ConstantOffsets;
                var   instructions          = block.Instructions;
                for (int i = 0; i < instructions.Length; i++)
                {
                    var  instr        = instructions[i];
                    uint bytesWritten = block.CodeWriter.BytesWritten;
                    bool isOriginalInstruction;
                    if (constantOffsets != null)
                    {
                        errorMessage = instr.TryEncode(encoder, out constantOffsets[i], out isOriginalInstruction);
                    }
                    else
                    {
                        errorMessage = instr.TryEncode(encoder, out _, out isOriginalInstruction);
                    }
                    if (errorMessage != null)
                    {
                        return(false);
                    }
                    uint size = block.CodeWriter.BytesWritten - bytesWritten;
                    if (size != instr.Size)
                    {
                        errorMessage = "Internal error: didn't write all bytes";
                        return(false);
                    }
                    if (newInstructionOffsets != null)
                    {
                        if (isOriginalInstruction)
                        {
                            newInstructionOffsets[i] = (uint)(ip - block.RIP);
                        }
                        else
                        {
                            newInstructionOffsets[i] = uint.MaxValue;
                        }
                    }
                    ip += size;
                }
                block.WriteData();
            }

            errorMessage = null;
            return(true);
        }