| Рабочим названием платформы .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 >