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