Рабочим названием платформы .NET было |
Опубликован: 28.06.2006 | Уровень: специалист | Доступ: платный | ВУЗ: Московский государственный технический университет им. Н.Э. Баумана
Дополнительный материал 2:
Приложение Б
< Дополнительный материал 1 || Дополнительный материал 2 || Дополнительный материал 3 >
Исходный код программы CilCodec
Исходный код программы CilCodec, выполняющей кодирование/декодирование потока инструкций языка CIL, располагается в файле CilCodec.cs:
using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; public class Instruction { public Instruction(OpCode code, int offset) { this.code = code; this.offset = offset; this.operand = null; } public OpCode Code { get { return code; } } public int Offset { get { return offset; } } public object Operand { get { return operand; } set { operand = value; } } public override string ToString() { return String.Format(" IL_{0:X8}: ",Offset) + Code.ToString().PadRight(10) + " " + formatOperand(); } #region Private members private OpCode code; private object operand; private int offset; private string formatOperand() { string s; switch (code.OperandType) { case OperandType.InlineNone: /* None */ return ""; case OperandType.ShortInlineBrTarget: /* int8 */ case OperandType.InlineBrTarget: /* int32 */ return String.Format("IL_{0:X8}",operand); case OperandType.InlineI: /* int32 */ return String.Format("0x{0:X8}",operand); case OperandType.InlineI8: /* int64 */ return String.Format("0x{0:X16}",operand); case OperandType.ShortInlineI: /* int8 */ return String.Format("0x{0:X2}",operand); case OperandType.ShortInlineVar: /* unsigned int8 */ case OperandType.InlineVar: /* unsigned int16 */ return String.Format("{0:d}",operand); case OperandType.ShortInlineR: /* float32 */ case OperandType.InlineR: /* float64 */ return String.Format("{0:e}",operand); case OperandType.InlineSwitch: /* switch */ s = "("; foreach (int target in (int[])operand) s += String.Format("IL_{0:X8}",target) + " "; return s + ")"; default: /* token */ s = String.Format("{0:X8}",operand); return "("+s.Substring(0,2)+")"+s.Substring(2); } } #endregion } public class CilCodec { public static Instruction[] DecodeCil(byte[] cilStream) { int offset = 0; ArrayList instructions = new ArrayList(); while (offset < cilStream.Length) { OpCode code; short s2 = cilStream[offset]; if (s2 == 0xFE) { byte s1 = cilStream[offset+1]; code = (OpCode)(codes[((s2 << 8) | s1)]); } else code = (OpCode)(codes[s2]); Instruction ins = new Instruction(code,offset); offset += code.Size; switch (code.OperandType) { case OperandType.InlineNone: /* None */ break; case OperandType.ShortInlineBrTarget: /* int8 */ ins.Operand = offset + 1 + (sbyte)cilStream[offset]; offset++; break; case OperandType.InlineI: /* int32 */ ins.Operand = BitConverter.ToInt32(cilStream,offset); offset += 4; break; case OperandType.InlineBrTarget: /* int32 */ ins.Operand = offset + 4 + BitConverter.ToInt32(cilStream,offset); offset += 4; break; case OperandType.InlineI8: /* int64 */ ins.Operand = BitConverter.ToInt64(cilStream,offset); offset += 8; break; case OperandType.ShortInlineI: /* int8 */ ins.Operand = (sbyte)cilStream[offset++]; break; case OperandType.ShortInlineVar: /* unsigned int8 */ ins.Operand = cilStream[offset++]; break; case OperandType.InlineVar: /* unsigned int16 */ ins.Operand = BitConverter.ToUInt16(cilStream,offset); offset += 2; break; case OperandType.ShortInlineR: /* float32 */ ins.Operand = BitConverter.ToSingle(cilStream,offset); offset += 4; break; case OperandType.InlineR: /* float64 */ ins.Operand = BitConverter.ToDouble(cilStream,offset); offset += 8; break; case OperandType.InlineSwitch: /* switch */ uint num = BitConverter.ToUInt32(cilStream,offset); offset += 4; int[] targets = new int[num]; for (int i = 0; i < num; i++) { targets[i] = BitConverter.ToInt32(cilStream,offset); offset += 4; } for (int i = 0; i < num; i++) targets[i] += offset; ins.Operand = targets; break; default: /* token */ byte b1 = cilStream[offset++], b2 = cilStream[offset++], b3 = cilStream[offset++], b4 = cilStream[offset++]; ins.Operand = ((int)b1 << 24) | ((int)b2 << 16) | ((int)b3 << 8) | (int)b4; break; } instructions.Add(ins); } Instruction[] instrArray = new Instruction [instructions.Count]; instructions.CopyTo(instrArray); return instrArray; } public static byte[] EncodeCil(Instruction[] instructions) { ArrayList Result = new ArrayList(); foreach(Instruction ins in instructions) { short codeValue = ins.Code.Value; Result.Add((byte)codeValue); object operand = ins.Operand; int dataOffset = ins.Offset + ins.Code.Size; switch (ins.Code.OperandType) { case OperandType.InlineNone: /* None */ break; case OperandType.ShortInlineBrTarget: /* int8 */ Result.Add((byte)((int)ins.Operand - dataOffset - 1)); break; case OperandType.InlineI: /* int32 */ byte[] operands = BitConverter.GetBytes((Int32)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.InlineBrTarget: /* int32 */ operands = BitConverter.GetBytes((Int32)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.InlineI8: /* int64 */ operands = BitConverter.GetBytes((Int64)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.ShortInlineI: /* int8 */ operands = BitConverter.GetBytes((sbyte)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.ShortInlineVar: /* unsigned int8 */ Result.Add((byte)operand); break; case OperandType.InlineVar: /* unsigned int16 */ operands = BitConverter.GetBytes((UInt16)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.ShortInlineR: /* float32 */ operands = BitConverter.GetBytes((Single)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.InlineR: /* float64 */ operands = BitConverter.GetBytes((double)operand); foreach( byte op in operands ) { Result.Add(op); } break; case OperandType.InlineSwitch: /* switch */ int[] targets = (int[])ins.Operand; //Write length of switching table operands = BitConverter.GetBytes(targets.Length); int nextOpOffset = dataOffset; foreach( byte op in operands ) { Result.Add(op); nextOpOffset++; } nextOpOffset += targets.Length*4; foreach(int target in targets) { operands = BitConverter.GetBytes(target-nextOpOffset); foreach( byte op in operands ) Result.Add(op); } break; default: /* token */ Result.Add((byte) ((int)ins.Operand >> 24)); Result.Add((byte) ((int)ins.Operand >> 16)); Result.Add((byte) ((int)ins.Operand >> 8)); Result.Add((byte) ((int)ins.Operand)); break; } } return Result.ToArray(typeof(byte)) as byte[]; } static CilCodec() { codes = new Hashtable(); Type opCodesType = Type.GetType("System.Reflection.Emit.OpCodes"); FieldInfo[] fields = opCodesType.GetFields( (BindingFlags.Static | BindingFlags.Public)); foreach (FieldInfo field in fields) { OpCode opCode = (OpCode)(field.GetValue(null)); codes.Add(opCode.Value,opCode); } } private static Hashtable codes; } class Demo { static void Main() { testCodec(test1); testCodec(test2); } static void testCodec(byte[] cilStream) { Console.WriteLine("Decoded CIL stream:"); Instruction[] instrArray = CilCodec.DecodeCil(cilStream); foreach (Instruction ins in instrArray) Console.WriteLine(ins); byte[] cilStream2 = CilCodec.EncodeCil(instrArray); bool areEqual = cilStream.Length == cilStream2.Length; for (int i = 0; areEqual && i < cilStream.Length; i++) areEqual = cilStream[i] == cilStream2[i]; Console.WriteLine(areEqual ? "Codec is correct" : "Codec is incorrect"); Console.WriteLine("---------------------------------------"); } #region Sample instruction streams static byte[] test1 = new byte[] { 0x23, 0, 0, 0, 0, 0, 0, 0xF0, 0x3F, /* IL_0000: ldc.r8 1. */ 0x0A, /* IL_0009: stloc.0 */ 0x2B, 0x1B, /* IL_000a: br.s IL_0027 */ 0x03, /* IL_000c: ldarg.1 */ 0x18, /* IL_000d: ldc.i4.2 */ 0x5D, /* IL_000e: rem */ 0x17, /* IL_000f: ldc.i4.1 */ 0x33, 0x0B, /* IL_0010: bne.un.s IL_001d */ 0x03, /* IL_0012: ldarg.1 */ 0x17, /* IL_0013: ldc.i4.1 */ 0x59, /* IL_0014: sub */ 0x10, 0x01, /* IL_0015: starg.s 1 */ 0x06, /* IL_0017: ldloc.0 */ 0x02, /* IL_0018: ldarg.0 */ 0x5A, /* IL_0019: mul */ 0x0A, /* IL_001a: stloc.0 */ 0x2B, 0x0A, /* IL_001b: br.s IL_0027 */ 0x03, /* IL_001d: ldarg.1 */ 0x18, /* IL_001e: ldc.i4.2 */ 0x5B, /* IL_001f: div */ 0x10, 0x01, /* IL_0020: starg.s 1 */ 0x02, /* IL_0022: ldarg.0 */ 0x02, /* IL_0023: ldarg.0 */ 0x5A, /* IL_0024: mul */ 0x10, 0x00, /* IL_0025: starg.s 0 */ 0x03, /* IL_0027: ldarg.1 */ 0x2D, 0xE2, /* IL_0028: brtrue.s IL_000c */ 0x2B, 0x0C, /* IL_002a: br.s IL_0038 */ 0x06, /* IL_002c: ldloc.0 */ 0x23, 0, 0, 0, 0, 0, 0, 0x24, 0x40, /* IL_002d: ldc.r8 10. */ 0x5B, /* IL_0036: div */ 0x0A, /* IL_0037: stloc.0 */ 0x06, /* IL_0038: ldloc.0 */ 0x23, 0, 0, 0, 0, 0, 0, 0x14, 0x40, /* IL_0039: ldc.r8 5. */ 0x30, 0xE8, /* IL_0042: bgt.s IL_002c */ 0x06, /* IL_0044: ldloc.0 */ 0x0B, /* IL_0045: stloc.1 */ 0x2B, 0x00, /* IL_0046: br.s IL_0048 */ 0x07, /* IL_0048: ldloc.1 */ 0x2A /* IL_0049: ret */ }; static byte[] test2 = new byte[] { 0x02, /* IL_0000: ldarg.0 */ 0x0B, /* IL_0001: stloc.1 */ 0x07, /* IL_0002: ldloc.1 */ 0x45, 0x03, 0, 0, 0, /* IL_0003: switch ( */ 0x02, 0, 0, 0, /* IL_0016, */ 0x06, 0, 0, 0, /* IL_001a, */ 0x0A, 0, 0, 0, /* IL_001e) */ 0x2B, 0x0C, /* IL_0014: br.s IL_0022 */ 0x17, /* IL_0016: ldc.i4.1 */ 0x0A, /* IL_0017: stloc.0 */ 0x2B, 0x0C, /* IL_0018: br.s IL_0026 */ 0x16, /* IL_001a: ldc.i4.0 */ 0x0A, /* IL_001b: stloc.0 */ 0x2B, 0x08, /* IL_001c: br.s IL_0026 */ 0x17, /* IL_001e: ldc.i4.1 */ 0x0A, /* IL_001f: stloc.0 */ 0x2B, 0x04, /* IL_0020: br.s IL_0026 */ 0x16, /* IL_0022: ldc.i4.0 */ 0x0A, /* IL_0023: stloc.0 */ 0x2B, 0x00, /* IL_0024: br.s IL_0026 */ 0x06, /* IL_0026: ldloc.0 */ 0x2A /* IL_0027: ret */ }; #endregion }
< Дополнительный материал 1 || Дополнительный материал 2 || Дополнительный материал 3 >