/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load static field //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the object to load Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); //Get the object size information int size = theTypeInfo.SizeOnStackInBytes; //Load the object onto the stack conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); for (int i = size - 4; i >= 0; i -= 4) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ECX+" + i.ToString() + "]", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } int extra = size % 4; for (int i = extra - 1; i >= 0; i--) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + i.ToString() + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Byte, Src = "AL" }); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = size, isGCManaged = false }); }
public override void Convert(ILConversionState conversionState, ILOp theOp) { //Save return address conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$ra" }); //Push the previous method's fp conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$fp" }); //Set fp for this method conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$sp", Dest = "$fp", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); //Allocate stack space for locals //Only bother if there are any locals if (conversionState.Input.TheMethodInfo.LocalInfos.Count > 0) { int totalBytes = 0; foreach (Types.VariableInfo aLocal in conversionState.Input.TheMethodInfo.LocalInfos) { totalBytes += aLocal.TheTypeInfo.SizeOnStackInBytes; } //We do not use "sub esp, X" (see below) because that leaves //junk memory - we need memory to be "initialised" to 0 //so that local variables are null unless properly initialised. //This prevents errors in the GC. for (int i = 0; i < totalBytes / 4; i++) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); } //result.AppendLine(string.Format("sub esp, {0}", totalBytes)); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when the metadata token is not for method metadata. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load token i.e. typeref //It should also support methodref and fieldrefs int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); try { Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); if (theType == null) { throw new NullReferenceException(); } string typeTableId = conversionState.TheILLibrary.GetTypeInfo(theType).ID; conversionState.AddExternalLabel(typeTableId); conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = typeTableId }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } catch { throw new NotSupportedException("The metadata token specifies a fieldref or methodref which isn't supported yet!"); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Push the previous method's ebp conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EBP" }); //Set ebp for this method //See calling convention spec - this allows easy access of //args and locals within the method without having to track //temporary values (which would be a nightmare with the //exception handling implementation that the kernel uses!) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "ESP", Dest = "EBP" }); //Allocate stack space for locals //Only bother if there are any locals if (conversionState.Input.TheMethodInfo.LocalInfos.Count > 0) { int totalBytes = 0; foreach (Types.VariableInfo aLocal in conversionState.Input.TheMethodInfo.LocalInfos) { totalBytes += aLocal.TheTypeInfo.SizeOnStackInBytes; } //We do not use "sub esp, X" (see below) because that leaves //junk memory - we need memory to be "initialised" to 0 //so that local variables are null unless properly initialised. //This prevents errors in the GC. for (int i = 0; i < totalBytes / 4; i++) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } //result.AppendLine(string.Format("sub esp, {0}", totalBytes)); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the object to load Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); //Get the object size information int size = theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); //Load the object onto the stack conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "ECX", Src = "[ESP+" + theTypeInfo.SizeOnStackInBytes + "]" }); if (size == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX]" }); } else if (size == 2) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX]" }); } else if (size >= 4) { for (int i = 0; i < size; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); switch (size - i) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX+" + i + "]" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX+" + i + "]" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX+" + i + "]" }); conversionState.Append(new ASMOps.Shr() { Src = "16", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX+" + (i + 1) + "]" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[ECX+" + i + "]" }); break; } } } else { throw new ArgumentOutOfRangeException("Storing object with unsupported size! Size: " + size.ToString()); } conversionState.Append(new ASMOps.Add() { Dest = "ESP", Src = "4" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if either or both values to shift left are floating point values or /// if the values are 8 bytes in size. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { StackItem theItem = conversionState.CurrentStackFrame.Stack.Peek(); if (theItem.isFloat) { //SUPPORT - Not op for floats throw new NotSupportedException("Not op not supported for float operands!"); } if (theItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Not() { Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (theItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); conversionState.Append(new ASMOps.Not() { Dest = "EAX" }); conversionState.Append(new ASMOps.Not() { Dest = "EBX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EBX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else { throw new NotSupportedException("Not op not supported for operand size!"); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.FieldInfo theFieldInfo = conversionState.GetFieldInfo(theField.DeclaringType, theField.Name); Types.TypeInfo theFieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theFieldInfo.FieldType); string fieldId = theFieldInfo.ID; int size = /*theFieldTypeInfo.IsValueType ? theFieldTypeInfo.SizeOnHeapInBytes : */theFieldTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); conversionState.AddExternalLabel(fieldId); StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing static fields of type float not supported yet!"); } conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = fieldId }); if (size == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t1", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 2) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "$t1", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "4($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { throw new ArgumentOutOfRangeException("Storing static field that has stack size greater than 8 not supported!"); } if (value.sizeOnStackInBytes - size > 0) { conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = (value.sizeOnStackInBytes - size).ToString(), Dest = "$sp" }); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { if (theOp.IsDebugOp) { conversionState.Append(new ASMOps.Int() { IntNum = "3" }); } else { conversionState.Append(new ASMOps.Nop()); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the object to load Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); //Get the object size information int memSize = theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes; //Load the object onto the stack conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); int irregularSize = memSize % 4; if (irregularSize > 0) { conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); switch (irregularSize) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + (memSize - 1).ToString() + "]", Dest = "AL" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[ECX+" + (memSize - 2).ToString() + "]", Dest = "AX" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + (memSize - 1).ToString() + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Shl() { Dest = "EAX", Src = "16" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[ECX+" + (memSize - 3).ToString() + "]", Dest = "AX" }); break; } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } for (int i = memSize - irregularSize - 4; i >= 0; i -= 4) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ECX+" + i.ToString() + "]", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } // Pop address conversionState.CurrentStackFrame.Stack.Pop(); // Push value conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = memSize, isGCManaged = false, isValue = theTypeInfo.IsValueType }); }
public static void LoadData(ILConversionState conversionState, ILOp theOp, string addressReg, string valueReg, int offset, int size, bool SignExtend = false) { if (size == 1) { conversionState.Append(new ASMOps.Mov() { Src = offset + "(" + addressReg + ")", Dest = "$t6", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg, Size = ASMOps.OperandSize.Byte, SignExtend = SignExtend }); } else { conversionState.Append(new ASMOps.Xor() { Src1 = "$t6", Src2 = "$t6", Dest = "$t6" }); int shiftBits = 0; if (offset % 2 == 1) { conversionState.Append(new ASMOps.Mov() { Src = offset + "(" + addressReg + ")", Dest = "$t7", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg, Size = ASMOps.OperandSize.Byte }); conversionState.Append(new ASMOps.Or() { Src1 = "$t7", Src2 = "$t6", Dest = "$t6" }); size -= 1; offset += 1; shiftBits += 8; } while (size > 1) { conversionState.Append(new ASMOps.Mov() { Src = offset + "(" + addressReg + ")", Dest = "$t7", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg, Size = ASMOps.OperandSize.Halfword, SignExtend = (SignExtend && size == 2) }); if (shiftBits > 0) { conversionState.Append(new ASMOps.Sll() { Src = "$t7", Dest = "$t7", Bits = shiftBits }); } conversionState.Append(new ASMOps.Or() { Src1 = "$t7", Src2 = "$t6", Dest = "$t6" }); size -= 2; offset += 2; shiftBits += 16; } if (size == 1) { conversionState.Append(new ASMOps.Mov() { Src = offset + "(" + addressReg + ")", Dest = "$t7", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg, Size = ASMOps.OperandSize.Byte, SignExtend = SignExtend }); if (shiftBits > 0) { conversionState.Append(new ASMOps.Sll() { Src = "$t7", Dest = "$t7", Bits = shiftBits }); } conversionState.Append(new ASMOps.Or() { Src1 = "$t7", Src2 = "$t6", Dest = "$t6" }); size -= 1; offset += 1; shiftBits += 8; } } conversionState.Append(new ASMOps.Mov() { Src = "$t6", Dest = valueReg, Size = ASMOps.OperandSize.Word, MoveType = ASMOps.Mov.MoveTypes.RegToReg }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// If either value is < 4 bytes in length or /// operands are not of the same size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop item to negate StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if(itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Negate float vals not suppported yet!"); } // Two's Complement negation // - "Not" value then add 1 if(itemA.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Neg() { Arg = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (itemA.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); // Not the value conversionState.Append(new ASMOps.Not() { Dest = "EAX" }); conversionState.Append(new ASMOps.Not() { Dest = "EDX" }); // Then add 1 conversionState.Append(new ASMOps.Mov() { Src = "1", Dest = "EBX", Size = ASMOps.OperandSize.Dword }); conversionState.Append(new ASMOps.Mov() { Src = "0", Dest = "ECX", Size = ASMOps.OperandSize.Dword }); //Add ecx:ebx to edx:eax //Add low bits conversionState.Append(new ASMOps.Add() { Src = "EBX", Dest = "EAX" }); //Add high bits including any carry from //when low bits were added conversionState.Append(new ASMOps.Add() { Src = "ECX", Dest = "EDX", WithCarry = true }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else { throw new NotSupportedException("Stack item size not supported by neg op!"); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { if (theOp.IsDebugOp) { int currOpPosition = conversionState.PositionOf(theOp); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Debug", IsDebugOp = true }); conversionState.Append(new ASMOps.Nop()); //conversionState.Append(new ASMOps.Int() { IntNum = "3" }); } else { conversionState.Append(new ASMOps.Nop()); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if divide operands are floating point numbers or if attempting to divide 64-bit numbers. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either operand is < 4 bytes long. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { StackItem testItem = conversionState.CurrentStackFrame.Stack.Pop(); if (testItem.isFloat) { //TODO - Support floats throw new NotSupportedException("Switch for floats no supported!"); } else if (testItem.sizeOnStackInBytes != 4) { //TODO - Support other sizes throw new NotSupportedException("Switch for non-int32s not supported!"); } conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); for (int i = 0; i < theOp.ValueBytes.Length / 4; i++) { int branchOffset = theOp.NextOffset + Utilities.ReadInt32(theOp.ValueBytes, i * 4); ILOp opToGoTo = conversionState.Input.At(branchOffset); int branchPos = conversionState.PositionOf(opToGoTo); conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = i.ToString() }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpEqual, DestILPosition = branchPos }); } }
public static void InsertPageFaultDetection(ILConversionState conversionState, string reg, int offset, ILOp.OpCodes opCode) { if (PageFaultDetectionEnabled) { conversionState.Append(new ASMOps.Call() { Target = PageFaultDetectionMethod }); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if field to load is a floating value or the field to load /// is not of size 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Pop(); Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); // 1. Check array reference is not null // 1.1. Move array ref into eax // 1.2. Compare eax (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 2. Load array length // 1.1. Move array ref into eax conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP]", Dest = "EAX" }); // 1.2. Compare eax (array ref) to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "ContinueExecution1" }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ContinueExecution1" }); //2. Load array length // - Pop array ref conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); // - Load length from array ref conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ECX+" + lengthOffset.ToString() + "]", Dest = "EAX" }); // - Push array length conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// If either value is < 4 bytes in length or /// operands are not of the same size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop item to duplicate StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if(itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Duplicate float vals not suppported yet!"); } if(itemA.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (itemA.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else { throw new NotSupportedException("Stack item size not supported by duplicate op!"); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); conversionState.Append(new ASMOps.Mov() { Src = (theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes).ToString(), Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { StackItem theItem = conversionState.CurrentStackFrame.Stack.Pop(); if (theItem.isNewGCObject) { //Decrement ref count //Get the ID of method to call as it will be labeled in the output ASM. Types.MethodInfo anInfo = conversionState.GetDecrementRefCountMethodInfo(); string methodID = anInfo.ID; conversionState.AddExternalLabel(anInfo.ID); //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodID }); } conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = theItem.sizeOnStackInBytes.ToString(), Dest = "$sp" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load null (i.e. 0 as dword) conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { int dwordsToRotate = theOp.ValueBytes == null ? 2 : BitConverter.ToInt32(theOp.ValueBytes, 0); int bytesShift = 0; for (int i = 0; i < dwordsToRotate; i++) { if (i == 0) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = bytesShift.ToString() + "($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (bytesShift + 4).ToString() + "($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t1", Dest = bytesShift.ToString() + "($sp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (i == dwordsToRotate - 1) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = bytesShift + "($sp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (bytesShift + 4).ToString() + "($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t1", Dest = bytesShift.ToString() + "($sp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } bytesShift += 4; } rotateStackItems(conversionState, theOp.StackSwitch_Items, 1); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { int dwordsToRotate = theOp.ValueBytes == null ? 2 : BitConverter.ToInt32(theOp.ValueBytes, 0); int bytesShift = 0; for (int i = 0; i < dwordsToRotate; i++) { if (i == 0) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + bytesShift.ToString() + "]", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (bytesShift + 4).ToString() + "]", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EBX", Dest = "[ESP+" + bytesShift.ToString() + "]" }); } else if (i == dwordsToRotate - 1) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[ESP+" + bytesShift.ToString() + "]" }); } else { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (bytesShift + 4).ToString() + "]", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EBX", Dest = "[ESP+" + bytesShift.ToString() + "]" }); } bytesShift += 4; } rotateStackItems(conversionState, theOp.StackSwitch_Items, 1); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load a string literal (- fixed string i.e. one programmed as "a string in code") //Get the string metadata token used to get the string from the assembly int StringMetadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the value of the string to load string theString = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveString(StringMetadataToken); //Add the string literal and get its ID string theStringID = conversionState.TheILLibrary.AddStringLiteral(theString); conversionState.AddExternalLabel(theStringID); //Push the address of the string (i.e. address of ID - ASM label) conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = theStringID }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 4, isFloat = false, isGCManaged = true }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if field to load is a floating value or the field to load /// is not of size 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Pop(); Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); // 1. Check array reference is not null // 1.1. Move array ref into $t0 // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 2. Load array length // 1.1. Move array ref into eax conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 1.2. Compare eax (array ref) to 0 // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "0", BranchType = ASMOps.BranchOp.BranchNotZero, DestILPosition = currOpPosition, Extension = "ContinueExecution1", UnsignedTest = false }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ContinueExecution1" }); //2. Load array length // - Pop array ref conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); // - Load length from array ref //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = lengthOffset.ToString() + "($t2)", Dest = "$t0" }); GlobalMethods.LoadData(conversionState, theOp, "$t2", "$t0", lengthOffset, 4); // - Push array length conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = true }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point or /// if the value is not 4 or 8 bytes in size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); Types.FieldInfo theFieldInfo = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name); int offset = theFieldInfo.OffsetInBytes; int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if (value.isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing fields of type float not supported yet!"); } //Get object pointer GlobalMethods.InsertPageFaultDetection(conversionState, "ESP", stackSize, (OpCodes)theOp.opCode.Value); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + stackSize.ToString() + "]", Dest = "ECX" }); //Pop and mov value for (int i = 0; i < memSize; i += 2) { if (memSize - i == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "AX" }); GlobalMethods.InsertPageFaultDetection(conversionState, "ECX", offset + i, (OpCodes)theOp.opCode.Value); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX+" + (offset + i).ToString() + "]" }); } else { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "AX" }); GlobalMethods.InsertPageFaultDetection(conversionState, "ECX", offset + i, (OpCodes)theOp.opCode.Value); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX+" + (offset + i).ToString() + "]" }); } } // Rounds down || Pop object pointer conversionState.Append(new ASMOps.Add() { Src = ((((stackSize - memSize) / 2) * 2) + 4).ToString(), Dest = "ESP" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point or /// if the value is not 4 or 8 bytes in size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); Types.FieldInfo theFieldInfo = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name); int offset = theFieldInfo.OffsetInBytes; int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if (value.isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing fields of type float not supported yet!"); } //Get object pointer conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSize.ToString() + "($sp)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); //Pop and mov value for (int i = 0; i < memSize; i += 2) { if (memSize - i == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Halfword, Dest = "$t0" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t0", Dest = (offset + i).ToString() + "($t2)" }); GlobalMethods.StoreData(conversionState, theOp, "$t2", "$t0", (offset + i), 1); } else { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Halfword, Dest = "$t0" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = (offset + i).ToString() + "($t2)" }); GlobalMethods.StoreData(conversionState, theOp, "$t2", "$t0", (offset + i), 2); } } // Rounds down || Pop object pointer conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = ((((stackSize - memSize) / 2) * 2) + 4).ToString(), Dest = "$sp" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if compare operands are floating point numbers or if either value is < 4 bytes in length or /// operands are not of the same size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); bool unsignedComparison = (OpCodes)theOp.opCode.Value == OpCodes.Clt_Un; int currOpPosition = conversionState.PositionOf(theOp); if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Add floats is unsupported!"); } else if(itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //If A >= B, jump to Else (not-true case) conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, Src1 = "$t0", Src2 = "$t1", DestILPosition = currOpPosition, Extension = "Else", UnsignedTest = unsignedComparison }); //Otherwise, A < B, so push true (true=1) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "$t4", Src = "1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); //And then jump to the end of this IL op. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); //Insert the Else label. conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Else" }); //Else case - Push false (false=0) conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); //Push the result onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); //If A high bytes < B high bytes : True //If A high bytes = B high bytes : Check, if A low bytes < B low bytes : True //Else : False //A high bytes < B high bytes? Branch to true case. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchLessThan, Src1 = "$t3", Src2 = "$t2", DestILPosition = currOpPosition, Extension = "True", UnsignedTest = unsignedComparison }); //A high bytes > B high bytes? Branch to else case. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchGreaterThan, Src1 = "$t3", Src2 = "$t2", DestILPosition = currOpPosition, Extension = "Else", UnsignedTest = unsignedComparison }); //Otherwise, A high bytes = B high bytes //A low bytes >= B low bytes? Branch to else case. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, Src1 = "$t0", Src2 = "$t1", DestILPosition = currOpPosition, Extension = "Else", UnsignedTest = unsignedComparison }); //Otherwise A < B. //Insert True case label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "True" }); //True case - Push true (true=1) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "$t4", Src = "1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); //And then jump to the end of this IL op. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); //Insert Else case label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Else" }); //Else case - Push false (false=0) conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); //Push the result onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, // Yes, this is supposed to be 4 - the value that just got pushed was a // true / false integer sizeOnStackInBytes = 4, isGCManaged = false }); } else { throw new NotSupportedException("Unsupported number of bytes for compare less than!"); } //Always append the end label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when the return value is a float or the size on the stack /// in bytes is not 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Store the return value //Get the return type Type retType = (conversionState.Input.TheMethodInfo.IsConstructor ? typeof(void) : ((MethodInfo)conversionState.Input.TheMethodInfo.UnderlyingInfo).ReturnType); Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); //Get the size of the return type on stack int retSize = retTypeInfo.SizeOnStackInBytes; //If the size isn't 0 (i.e. isn't "void" which has no return value) if (retSize != 0) { //Pop the return value off our stack StackItem retItem = conversionState.CurrentStackFrame.Stack.Pop(); //If it is float, well, we don't support it yet... if (retItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Floats return type not supported yet!"); } //Otherwise, store the return value at [ebp+8] //[ebp+8] because that is last "argument" // - read the calling convention spec else if (retSize == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "8($fp)", Src = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (retSize == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "8($fp)", Src = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "12($fp)", Src = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { throw new NotSupportedException("Return type size not supported / invalid!"); } } //Once return value is off the stack, remove the locals //Deallocate stack space for locals //Only bother if there are any locals if (conversionState.Input.TheMethodInfo.LocalInfos.Count > 0) { //Get the total size of all locals int totalBytes = 0; foreach (Types.VariableInfo aLocal in conversionState.Input.TheMethodInfo.LocalInfos) { totalBytes += aLocal.TheTypeInfo.SizeOnStackInBytes; } //Move esp past the locals conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = totalBytes.ToString(), Dest = "$sp" }); } //Restore ebp to previous method's ebp conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$fp" }); //This pop also takes last value off the stack which //means top item is the return address //So ret command can now be correctly executed. }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { int currOpPosition = conversionState.PositionOf(theOp); // Test if the object provided inherits from the specified class // 1. Pop object ref // 1.1. Test if object ref is null: // 1.1.1 True: Push null and continue // 1.1.2 False: Go to 2 // 2. Load object type // 3. Test if object type == provided type: // 3.1 True: Push object ref and continue // 3.2 False: // 3.2.1. Move to base type // 3.2.2. Test if base type null: // 3.2.2.1 True: Push null and continue // 3.2.2.2 False: Jump back to (3) // 1. Pop object ref conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); // 1.1. Test if object ref is null: conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "0", BranchType = ASMOps.BranchOp.BranchNotEqual, DestILPosition = currOpPosition, Extension = "False1", UnsignedTest = true }); // 1.1.1 True: Push null and continue conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); // 1.1.2 False: Go to 2 conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "False1" }); // 2. Load object type //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 4); // 3. Test if object type == provided type: int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); string TestTypeId = theTypeInfo.ID; conversionState.AddExternalLabel(TestTypeId); conversionState.Append(new ASMOps.La() { Label = TestTypeId, Dest = "$t2" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Label3" }); conversionState.Append(new ASMOps.Branch() { Src1 = "$t1", Src2 = "$t2", BranchType = ASMOps.BranchOp.BranchNotEqual, DestILPosition = currOpPosition, Extension = "False2", UnsignedTest = true }); // 3.1 True: Push object ref and continue conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); // 3.2 False: conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "False2" }); // 3.2.1. Move to base type int baseTypeOffset = conversionState.GetTypeFieldOffset("TheBaseType"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = baseTypeOffset + "($t1)", Dest = "$t1" }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t1", baseTypeOffset, 4); // 3.2.2. Test if base type null: // 3.2.2.2 False: Jump back to (3) conversionState.Append(new ASMOps.Branch() { Src1 = "$t1", Src2 = "0", BranchType = ASMOps.BranchOp.BranchNotEqual, DestILPosition = currOpPosition, Extension = "Label3", UnsignedTest = true }); // 3.2.2.1 True: Push null and continue conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if either or both values to shift left are floating point values or /// if the values are 8 bytes in size. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); int currOpPosition = conversionState.PositionOf(theOp); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Shift left on floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Sllv() { Src = "$t0", BitsReg = "$t2", Dest = "$t0", }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! 4,8 not supported."); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4)) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); //Pop item A (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); //Check shift size conversionState.Append(new ASMOps.Branch() { Src1 = "$t2", Src2 = "32", BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, DestILPosition = currOpPosition, Extension = "ShiftMoreThan32", UnsignedTest = true }); //Shld (< 32) //Works for shifting 64 bit values //Left shift high bits ($t3) by $t2 conversionState.Append(new ASMOps.Sllv() { Src = "$t3", BitsReg = "$t2", Dest = "$t3" }); //Right shift low bits ($t0) by (32-$t2) into temp ($t1) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "32", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Sub() { Src1 = "$t1", Src2 = "$t2", Dest = "$t1" }); conversionState.Append(new ASMOps.Srlv() { Src = "$t0", BitsReg = "$t1", Dest = "$t1" }); //$t1 = temp //Copy temp to high bits conversionState.Append(new ASMOps.Or() { Src1 = "$t1", Src2 = "$t3", Dest = "$t3"}); //Left shift low bytes by $t2 conversionState.Append(new ASMOps.Sllv() { Src = "$t0", BitsReg = "$t2", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); //Shld (>= 32) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftMoreThan32" }); //Move low bits ($t0) to high bits ($t3) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "$t3", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); //Zero out low bits conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //Left shift high bits by (t2-32) conversionState.Append(new ASMOps.Sub() { Src1 = "$t2", Src2 = "32", Dest = "$t2" }); conversionState.Append(new ASMOps.Sllv() { Src = "$t3", BitsReg = "$t2", Dest = "$t3" }); //Push result conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Note: Shifting by more than 64 bits is pointless since the value will be annihilated entirely. // "64" fits well within the low 32-bits // So for this op, we do the same as the 8-4 byte version but discard the top four bytes // of the second operand // Except we must check the high bytes for non-zero value. If they are non-zero, we simply // push a result of zero. //Pop item B (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop item A (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); //Check high 4 bytes of second param conversionState.Append(new ASMOps.Branch() { Src1 = "$t1", BranchType = ASMOps.BranchOp.BranchZero, DestILPosition = currOpPosition, Extension = "Zero" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End2" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "zero" }); conversionState.Append(new ASMOps.Branch() { Src1 = "$t2", Src2 = "32", BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, DestILPosition = currOpPosition, Extension = "ShiftMoreThan32", UnsignedTest = true }); //Shld (< 32) //Works for shifting 64 bit values //Left shift high bits ($t3) by $t2 conversionState.Append(new ASMOps.Sllv() { Src = "$t3", BitsReg = "$t2", Dest = "$t3" }); //Right shift low bits ($t0) by (32-$t2) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "32", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Sub() { Src1 = "$t1", Src2 = "$t2", Dest = "$t1" }); conversionState.Append(new ASMOps.Srlv() { Src = "$t0", BitsReg = "$t1", Dest = "$t1" }); //$t1 = temp //Copy temp to high bits conversionState.Append(new ASMOps.Or() { Src1 = "$t1", Src2 = "$t3", Dest = "$t3"}); conversionState.Append(new ASMOps.Sllv() { Src = "$t0", BitsReg = "$t2", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End1" }); //Shl (>= 32) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftMoreThan32" }); //Move low bits ($t0) to high bits ($t3) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "$t3", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); //Zero out low bits conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //Left shift high bits by (t2-32) conversionState.Append(new ASMOps.Sub() { Src1 = "$t2", Src2 = "32", Dest = "$t2" }); conversionState.Append(new ASMOps.Sllv() { Src = "$t3", BitsReg = "$t2", Dest = "$t3" }); //Push result conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End1" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End2" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if any argument or the return value is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); conversionState.AddExternalLabel(methodToCallInfo.ID); //The method to call is a method base //A method base can be either a method info i.e. a normal method //or a constructor method. The two types are treated separately. if(methodToCall is MethodInfo) { //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); //Go through each one if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } } } //No params to skip over but we might still need to store return value else if (returnItem.sizeOnStackInBytes != 0) { //The return value will be the top item on the stack. //So all we need to do is push the return item onto our stack. conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if(methodToCall is ConstructorInfo) { ConstructorInfo aConstructor = (ConstructorInfo)methodToCall; if (aConstructor.IsStatic) { //Static constructors do not have parameters or return values //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); } else { //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); //After a call, we need to remove the parameters from the stack //This is most easily done by just adding the total number of bytes for params //to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called ParameterInfo[] allParams = methodToCall.GetParameters(); //Go through each one foreach (ParameterInfo aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam.ParameterType).SizeOnStackInBytes; } //Add 4 bytes for the instance ref bytesToAdd += 4; //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); } } } }