/// <summary> /// See base class documentation. /// <para>To Do's:</para> /// <list type="bullet"> /// <item> /// <term>To do</term> /// <description>Implement storing of float arguments.</description> /// </item> /// </list> /// </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.NotImplementedException"> /// Thrown when storing a float argument is required as it currently hasn't been /// implemented. /// </exception> /// <exception cref="System.ArgumentException"> /// Thrown when an invalid number of bytes is specified for the argument to store. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Get the index of the argument to load Int16 index = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Starg: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Starg_S: index = (Int16)theOp.ValueBytes[0]; break; } Types.VariableInfo argInfo = conversionState.Input.TheMethodInfo.ArgumentInfos[index]; //Used to store the number of bytes to add to EBP to get to the arg int BytesOffsetFromEBP = argInfo.Offset; //Pop the argument value from the stack int bytesForArg = argInfo.TheTypeInfo.SizeOnStackInBytes; for (int i = 0; i < bytesForArg; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "[EBP+" + (BytesOffsetFromEBP + i) + "]" }); } //Pop the arg value from our stack conversionState.CurrentStackFrame.Stack.Pop(); }
/// <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.Push() { Size = ASMOps.OperandSize.Dword, Src = typeTableId }); 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> /// <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.Word, Dest = "$t0" }); 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.Branch() { BranchType = ASMOps.BranchOp.BranchEqual, Src2 = i.ToString(), Src1 = "$t0", DestILPosition = branchPos }); } }
/// <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, isValue = 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 the value to store is floating point. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { UInt16 localIndex = 0; switch ((ILOp.OpCodes)theOp.opCode.Value) { case OpCodes.Stloc: localIndex = (UInt16)Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Stloc_0: localIndex = 0; break; case OpCodes.Stloc_1: localIndex = 1; break; case OpCodes.Stloc_2: localIndex = 2; break; case OpCodes.Stloc_3: localIndex = 3; break; case OpCodes.Stloc_S: localIndex = (UInt16)theOp.ValueBytes[0]; break; } Types.VariableInfo localInfo = conversionState.Input.TheMethodInfo.LocalInfos[localIndex]; StackItem theItem = conversionState.CurrentStackFrame.Stack.Pop(); if (theItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Float locals not supported yet!"); } int locSize = localInfo.TheTypeInfo.SizeOnStackInBytes; if (locSize == 0) { conversionState.Append(new ASMOps.Comment("0 pop size (?!)")); } else { for (int i = 0; i < locSize; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "[EBP-" + Math.Abs(localInfo.Offset + i).ToString() + "]" }); } } }
/// <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> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Ignore for now //TODO: Do we need to do any proper initialisation? conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "4", Dest = "$sp", Unsigned = 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) { //Ignore for now //TODO: Do we need to do any proper initialisation? conversionState.Append(new ASMOps.Add() { Src = "4", 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> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Ignore for now //TODO: Initialise the structure to 0 conversionState.Append(new ASMOps.Add() { Src = "4", 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> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Ignore for now //TODO: Initialise the structure to 0 conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "4", Dest = "$sp", Unsigned = 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 either or both values to not are floating point values or /// if the values are 8 bytes in 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!"); } }
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> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Get the ID (i.e. ASM label) of the method to load a pointer to Types.MethodInfo methodInfo = conversionState.TheILLibrary.GetMethodInfo(theOp.MethodToCall); string methodID = methodInfo.ID; bool addExternalLabel = methodID != conversionState.Input.TheMethodInfo.ID; //If we want to load the pointer at a specified IL op number: if (theOp.LoadAtILOpAfterOp != null) { ILBlock anILBlock = conversionState.TheILLibrary.GetILBlock(methodInfo); int index = anILBlock.ILOps.IndexOf(theOp.LoadAtILOpAfterOp); if (index == -1) { throw new NullReferenceException("LoadAtILOpAfterOp not found in IL block!"); } index++; methodID = ASM.ASMBlock.GenerateLabel(methodID, anILBlock.PositionOf(anILBlock.ILOps[index])); } else if (theOp.LoadAtILOffset != int.MaxValue) { //Append the IL sub-label to the ID ILBlock anILBlock = conversionState.TheILLibrary.GetILBlock(methodInfo); methodID = ASM.ASMBlock.GenerateLabel(methodID, anILBlock.PositionOf(anILBlock.At(theOp.LoadAtILOffset))); //Note: This is used by try/catch/finally blocks for pushing pointers // to catch/finally handlers and filters } if (addExternalLabel) { conversionState.AddExternalLabel(methodID); } //Push the pointer to the function conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = methodID }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); }
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"> /// 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 }); }
/// <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 word) conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); }
/// <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) { 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) { 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> 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.Push() { Size = ASMOps.OperandSize.Dword, Src = (theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes).ToString() }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, 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)); } }
private static void rotateStackItems(ILConversionState state, int items, int distance) { if (distance >= items) { throw new IndexOutOfRangeException("IlPreprocessor.rotateStackItems: distance >= items invalid!"); } List <StackItem> poppedItems = new List <StackItem>(); for (int i = 0; i < items; i++) { poppedItems.Add(state.CurrentStackFrame.Stack.Pop()); } for (int i = distance; i > -1; i--) { state.CurrentStackFrame.Stack.Push(poppedItems[i]); } for (int i = items - 1; i > distance; i--) { state.CurrentStackFrame.Stack.Push(poppedItems[i]); } }
/// <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)); } }
public static void StoreData(ILConversionState conversionState, ILOp theOp, string addressReg, string valueReg, int offset, int size) { if (size == 1) { conversionState.Append(new ASMOps.Mov() { Src = valueReg, Dest = offset + "(" + addressReg + ")", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory, Size = ASMOps.OperandSize.Byte }); } else { conversionState.Append(new ASMOps.Mov() { Dest = "$t6", Src = valueReg, Size = ASMOps.OperandSize.Word, MoveType = ASMOps.Mov.MoveTypes.RegToReg }); if (offset % 2 == 1) { conversionState.Append(new ASMOps.Mov() { Dest = offset + "(" + addressReg + ")", Src = "$t6", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory, Size = ASMOps.OperandSize.Byte }); conversionState.Append(new ASMOps.Srl() { Src = "$t6", Dest = "$t6", Bits = 8 }); size -= 1; offset += 1; } while (size > 1) { conversionState.Append(new ASMOps.Mov() { Dest = offset + "(" + addressReg + ")", Src = "$t6", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory, Size = ASMOps.OperandSize.Halfword }); conversionState.Append(new ASMOps.Srl() { Src = "$t6", Dest = "$t6", Bits = 16 }); size -= 2; offset += 2; } if(size == 1) { conversionState.Append(new ASMOps.Mov() { Dest = offset + "(" + addressReg + ")", Src = "$t6", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory, Size = ASMOps.OperandSize.Byte }); conversionState.Append(new ASMOps.Srl() { Src = "$t6", Dest = "$t6", Bits = 8 }); size -= 1; offset += 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) { 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() { Src = theItem.sizeOnStackInBytes.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 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) { //Get the field's token that is used to get FieldInfo from the assembly int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the field info from the referencing assembly FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); //Get the database type information about the object that contains the field Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); int offset = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name).OffsetInBytes; //Is the value to load a floating pointer number? bool valueisFloat = Utilities.IsFloat(theField.FieldType); //Get the size of the value to load (in bytes, as it will appear on the stack) Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = theField.FieldType.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; //Pop the object pointer from our stack StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); //If the value to load is a float, erm...abort... if (valueisFloat) { //SUPPORT - floats throw new NotSupportedException("Loading fields of type float not supported yet!"); } //Pop object pointer conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); if ((OpCodes)theOp.opCode.Value == OpCodes.Ldflda) { conversionState.Append(new ASMOps.Add() { Src1 = "$t2", Src2 = offset.ToString(), Dest = "$t2" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else { //Push value at pointer+offset int sizeNotInMem = stackSize - memSize; int sizeToSub = (sizeNotInMem / 2) * 2; //Rounds down for (int i = 0; i < sizeToSub; i += 2) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Halfword, Src = "$zero" }); } for (int i = memSize + (memSize % 2); i > 0; i -= 2) { if (sizeToSub != sizeNotInMem) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = (offset + i - 2).ToString() + "($t2)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t2", "$t0", (offset + i - 2), 1); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Halfword, Src = "$t0" }); } else { //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = (offset + i - 2).ToString() + "($t2)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t2", "$t0", (offset + i - 2), 2); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Halfword, Src = "$t0" }); } } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = valueisFloat, sizeOnStackInBytes = stackSize, isGCManaged = fieldTypeInfo.IsGCManaged }); } }
/// <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 float local is required as it currently hasn't been /// implemented. /// Also thrown if arguments are not of size 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load local bool loadAddr = (ILOp.OpCodes)theOp.opCode.Value == OpCodes.Ldloca || (ILOp.OpCodes)theOp.opCode.Value == OpCodes.Ldloca_S; UInt16 localIndex = 0; switch ((ILOp.OpCodes)theOp.opCode.Value) { case OpCodes.Ldloc: case OpCodes.Ldloca: localIndex = (UInt16)Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldloc_0: localIndex = 0; break; case OpCodes.Ldloc_1: localIndex = 1; break; case OpCodes.Ldloc_2: localIndex = 2; break; case OpCodes.Ldloc_3: localIndex = 3; break; case OpCodes.Ldloc_S: case OpCodes.Ldloca_S: localIndex = (UInt16)theOp.ValueBytes[0]; break; } Types.VariableInfo theLoc = conversionState.Input.TheMethodInfo.LocalInfos[localIndex]; if (Utilities.IsFloat(theLoc.UnderlyingType)) { //SUPPORT - floats throw new NotSupportedException("Float locals not supported yet!"); } if (loadAddr) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EBP", Dest = "EAX" }); conversionState.Append(new ASMOps.Sub() { Src = (-theLoc.Offset).ToString(), Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = false }); } else { int localSizeOnStack = theLoc.TheTypeInfo.SizeOnStackInBytes; if ((localSizeOnStack % 4) != 0) { throw new NotSupportedException("Invalid local bytes size!"); } else { for (int i = theLoc.Offset + (localSizeOnStack - 4); i >= theLoc.Offset; i -= 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "[EBP-" + Math.Abs(i).ToString() + "]" }); } } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = Utilities.IsFloat(theLoc.UnderlyingType), sizeOnStackInBytes = localSizeOnStack, isGCManaged = theLoc.TheTypeInfo.IsGCManaged, isValue = theLoc.TheTypeInfo.IsValueType }); } }
/// <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 the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type Type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetNewArrMethodInfo().ID); //New array must: // - Allocate memory on the heap for the object // - If no memory is left, throw a panic attack because we're out of memory... // - Call the specified constructor int currOpPosition = conversionState.PositionOf(theOp); //Attempt to allocate memory on the heap for the new array //This involves: // - (Number of elements is already on the stack) // - Pushing the element type reference onto the stack // - Calling GC NewArr method // - Check the pointer == 0, if so, out of memory //Push type reference string typeIdStr = conversionState.TheILLibrary.GetTypeInfo(elementType).ID; conversionState.AddExternalLabel(typeIdStr); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = typeIdStr }); //Push a dword for return value (i.e. new array pointer) conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); //Get the GC.NewArr method ID (i.e. ASM label) string methodLabel = conversionState.GetNewArrMethodInfo().ID; //Call GC.NewArr conversionState.Append(new ASMOps.Call() { Target = methodLabel }); //Pop the return value (i.e. new array pointer) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Remove args from stack conversionState.Append(new ASMOps.Add() { Src = "8", Dest = "ESP" }); //Check if pointer == 0? conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); //If it isn't 0, not out of memory so continue execution conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "NotNullMem" }); //If we are out of memory, we have a massive problem //Because it means we don't have space to create a new exception object //So ultimately we just have to throw a kernel panic //Throw a panic attack... ( :/ ) by calling kernel Halt(uint lastAddress) //result.AppendLine("call GetEIP"); //result.AppendLine("push dword esp"); //result.AppendLine("push dword ebp"); //result.AppendLine("pushad"); //result.AppendLine("mov dword eax, 0xDEADBEEF"); //result.AppendLine("mov dword ebx, 0x2"); //result.AppendLine("mov dword ecx, 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_GC_Enabled], 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_Heap_PreventAllocation], 0"); //result.AppendLine("jmp method_System_Void_RETEND_Kernel_PreReqs_DECLEND_PageFaultDetection_NAMEEND___Fail"); conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); //Insert the not null label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotNullMem" }); //Push new array pointer conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true, isValue = 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) { MethodBase constructorMethod = theOp.MethodToCall; Type objectType = constructorMethod.DeclaringType; //New obj must: // - Ignore for creation of Delegates // - Allocate memory on the heap for the object // - If no memory is left, throw a panic attack because we're out of memory... // - Call the specified constructor if (typeof(Delegate).IsAssignableFrom(objectType)) { conversionState.Append(new ASMOps.Comment("Ignore newobj calls for Delegates")); //Still need to: // - Remove the "object" param but preserve the "function pointer" StackItem funcPtrItem = conversionState.CurrentStackFrame.Stack.Pop();; conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Push(funcPtrItem); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "4($sp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "4", Dest = "$sp" }); return; } Types.MethodInfo constructorMethodInfo = conversionState.TheILLibrary.GetMethodInfo(constructorMethod); conversionState.AddExternalLabel(conversionState.GetNewObjMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(constructorMethodInfo.ID); int currOpPosition = conversionState.PositionOf(theOp); //Attempt to allocate memory on the heap for the new object //This involves: // - Pushing the type reference onto the stack // - Calling GC NewObj method // - Check the pointer == 0, if so, out of memory //Push type reference string typeIdStr = conversionState.TheILLibrary.GetTypeInfo(objectType).ID; conversionState.AddExternalLabel(typeIdStr); conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = typeIdStr }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); //Push a word for return value (i.e. new object pointer) conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); //Get the GC.NewObj method ID (i.e. ASM label) string methodLabel = conversionState.GetNewObjMethodInfo().ID; //Call GC.NewObj conversionState.Append(new ASMOps.Call() { Target = methodLabel }); //Pop the return value (i.e. new object pointer) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Remove arg 0 from stack conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "4", Dest = "$sp" }); //Check if pointer == 0? //If it isn't 0, not out of memory so continue execution conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t0", DestILPosition = currOpPosition, Extension = "NotNullMem" }); //If we are out of memory, we have a massive problem //Because it means we don't have space to create a new exception object //So ultimately we just have to throw a kernel panic //Throw a panic attack... ( :/ ) by calling kernel Halt(uint lastAddress) //result.AppendLine("call GetEIP"); //result.AppendLine("push dword esp"); //result.AppendLine("push dword ebp"); //result.AppendLine("pushad"); //result.AppendLine("mov dword eax, 0xDEADBEEF"); //result.AppendLine("mov dword ebx, 0x1"); //result.AppendLine("mov dword ecx, 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_GC_Enabled], 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_Heap_PreventAllocation], 0"); //result.AppendLine("jmp method_System_Void_RETEND_Kernel_PreReqs_DECLEND_PageFaultDetection_NAMEEND___Fail"); conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); //Insert the not null label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotNullMem" }); //Call the specified constructor //This involves: // - Push empty dword onto stack // - Move all args down by one dword // - Move object reference into dword as first arg // - Call constructor conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); int sizeOfArgs = 0; ParameterInfo[] allParams = constructorMethod.GetParameters(); foreach (ParameterInfo aParam in allParams) { sizeOfArgs += conversionState.TheILLibrary.GetTypeInfo(aParam.ParameterType).SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Pop(); } conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$sp", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); if (sizeOfArgs > 0) { if (sizeOfArgs % 4 != 0) { throw new InvalidOperationException("sizeOfArgs not exact multiple of 4!"); } conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (sizeOfArgs / 4).ToString(), Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftArgsLoop" }); //Decrement counter ($t2) conversionState.Append(new ASMOps.Sub() { Src1 = "$t2", Src2 = "1", Dest = "$t2" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t1)", Dest = "$t3" }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t3", 4, 4); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t3", Dest = "0($t1)" }); GlobalMethods.StoreData(conversionState, theOp, "$t1", "$t3", 0, 4); conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = "4", Dest = "$t1" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t2", DestILPosition = currOpPosition, Extension = "ShiftArgsLoop" }); } //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t1)" }); GlobalMethods.StoreData(conversionState, theOp, "$t1", "$t0", 0, 4); conversionState.Append(new ASMOps.Call() { Target = constructorMethodInfo.ID }); //Only remove args from stack - we want the object pointer to remain on the stack conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = sizeOfArgs.ToString(), Dest = "$sp" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, 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 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.Dword, Dest = "ECX" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); 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.Dword, Dest = "ECX" }); //Pop item A (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); //Check shift size conversionState.Append(new ASMOps.Cmp() { Arg1 = "ECX", Arg2 = "32" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "ShiftMoreThan32", UnsignedTest = true }); //Shld (< 32) conversionState.Append(new ASMOps.Shl() { Src = "EAX", Dest = "EDX", Count = "CL" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "End" }); //Shld (>= 32) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftMoreThan32" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "EDX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EAX" }); conversionState.Append(new ASMOps.Sub() { Src = "32", Dest = "ECX" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EDX" }); //Push result conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); 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 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop item A (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); //Check high 4 bytes of second param conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "Zero" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "End2" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Zero" }); conversionState.Append(new ASMOps.Cmp() { Arg1 = "ECX", Arg2 = "32" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "ShiftMoreThan32", UnsignedTest = true }); //Shld (< 32) conversionState.Append(new ASMOps.Shl() { Src = "EAX", Dest = "EDX", Count = "CL" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "End1" }); //Shl (>= 32) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftMoreThan32" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "EDX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EAX" }); conversionState.Append(new ASMOps.Sub() { Src = "32", Dest = "ECX" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EDX" }); //Push result conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End1" }); 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.Label() { ILPosition = currOpPosition, Extension = "End2" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } } }