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)); }
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); }
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); }
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; } } }
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); }