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(); 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("Add floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Xor() { Src = "EBX", 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 = itemA.isValue && itemB.isValue }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the same size."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B to ecx:ebx conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); //Pop item A to edx:eax conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); //Or ecx:ebx with edx:eax conversionState.Append(new ASMOps.Xor() { Src = "EBX", Dest = "EAX" }); conversionState.Append(new ASMOps.Xor() { Src = "ECX", 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.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false, isValue = itemA.isValue && itemB.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> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool signExtend = true; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { signExtend = false; //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 elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { signExtend = false; //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 elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: //TODO - Add more LdElem op variants support throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; signExtend = false; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; signExtend = false; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: signExtend = false; elementType = null; break; case OpCodes.Ldelem_U4: signExtend = false; elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("LdElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Push the element onto the stack //Stack setup upon entering this op: (top-most downwards) // 0. Index of element to get as Int32 (word) // 1. Array object reference as address (word) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 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 // 1.1. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", BranchType = ASMOps.BranchOp.BranchNotZero, DestILPosition = currOpPosition, Extension = "Continue1", UnsignedTest = true }); // 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 = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into $t0 // 2.2. Move element type ref from array object into $t1 // 2.3. Compare $t0 to $t1 // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into $t0 int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; // 3. Check index to get is > -1 and < array length // 3.1. Move index into $t0 // 3.2. Move array length into $t1 // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 3.2. Move array length into $t2 // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into $t1 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // - Move length value (offset($t1)) into $t1 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = lengthOffset.ToString() + "($t1)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t1", lengthOffset, 4); // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "$zero", BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1", UnsignedTest = false }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "$t1", BranchType = ASMOps.BranchOp.BranchLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2", UnsignedTest = false }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Pop index into $t1 // 4.2. Pop array ref into $t0 // 4.3. Move element type ref (from array ref) into $t0 // 4.4. Move IsValueType (from element ref type) into $t2 // 4.5. If IsValueType, continue to 4.6., else goto 4.8. // 4.6. Move Size (from element type ref) into $t0 // 4.7. Skip over 4.8. // 4.8. Move StackSize (from element type ref) into $t0 // 4.9. Mulitply $t0 by $t1 (index by element size) // 4.10. Move array ref into $t1 // 4.11. Add enough to go past Kernel.FOS_System.Array fields // 4.12. Add $t0 and $t1 (array ref + fields + (index * element size)) // 4.1. Pop index into $t1 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); // 4.2. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 4.3. Move element type ref (from array ref) into $t0 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = elemTypeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", elemTypeOffset, 4); // 4.4. Move IsValueType (from element ref type) into $t2 int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = isValueTypeOffset.ToString() + "($t0)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t2", isValueTypeOffset, 1); // 4.5. If IsValueType, continue to 4.6., else goto 4.8. conversionState.Append(new ASMOps.Branch() { Src1 = "$t2", BranchType = ASMOps.BranchOp.BranchZero, DestILPosition = currOpPosition, Extension = "Continue4_1", UnsignedTest = true }); // 4.6. Move Size (from element type ref) into $t0 int sizeOffset = conversionState.GetTypeFieldOffset("Size"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = sizeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", sizeOffset, 4); // 4.7. Skip over 4.8. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.8. Move StackSize (from element type ref) into $t0 conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSizeOffset + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", stackSizeOffset, 4); // 4.9. Mulitply $t0 by $t1 (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Src1 = "$t1", Src2 = "$t0", Signed = true }); // 4.10. Pop array ref into $t1 conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); // 4.11. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = allFieldsOffset.ToString(), Dest = "$t1" }); // 4.12. Add $t0 and $t1 (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = "$t0", Dest = "$t0" }); // 5. Push the element onto the stack // 5.1. Push value at ($t0) (except for LdElemA op in which case just push address) if (pushValue) { switch (sizeToPush) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 1, signExtend); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 2, signExtend); break; case 4: //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); break; case 8: //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); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t0)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t2", 4, 4); break; } if (sizeToPush == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t1" }); } else { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } Types.TypeInfo elemTypeInfo = elementType == null ? null : conversionState.TheILLibrary.GetTypeInfo(elementType); // 5.2. Pop index and array ref from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? (elementType == null || elemTypeInfo.IsGCManaged) : false, isValue = pushValue ? (elementType != null && elemTypeInfo.IsValueType) : 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 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.Dword, Dest = "ECX" }); if ((OpCodes)theOp.opCode.Value == OpCodes.Ldflda) { conversionState.Append(new ASMOps.Add() { Src = offset.ToString(), Dest = "ECX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "ECX" }); 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.Word, Src = "0" }); } for (int i = memSize + (memSize % 2); i > 0; i -= 2) { if (sizeToSub != sizeNotInMem) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "AX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + (offset + i - 2).ToString() + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "AX" }); } else { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[ECX+" + (offset + i - 2).ToString() + "]", Dest = "AX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "AX" }); } } 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 if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Stores the integer value to push onto the stack long iValue = 0; //Stores the float value to push onto the stack double fValue = 0; //Indicates whether we should be pushing a float or integer value bool isFloat = false; //The number of bytes to push (e.g. 4 for Int32, 8 for Int64) int numBytes = 0; //Load the constant and type of constant switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldc_I4: iValue = Utilities.ReadInt32(theOp.ValueBytes, 0); numBytes = 4; break; case OpCodes.Ldc_I4_0: iValue = 0; numBytes = 4; break; case OpCodes.Ldc_I4_1: iValue = 1; numBytes = 4; break; case OpCodes.Ldc_I4_2: iValue = 2; numBytes = 4; break; case OpCodes.Ldc_I4_3: iValue = 3; numBytes = 4; break; case OpCodes.Ldc_I4_4: iValue = 4; numBytes = 4; break; case OpCodes.Ldc_I4_5: iValue = 5; numBytes = 4; break; case OpCodes.Ldc_I4_6: iValue = 6; numBytes = 4; break; case OpCodes.Ldc_I4_7: iValue = 7; numBytes = 4; break; case OpCodes.Ldc_I4_8: iValue = 8; numBytes = 4; break; case OpCodes.Ldc_I4_M1: iValue = -1; numBytes = 4; break; case OpCodes.Ldc_I4_S: iValue = (Int32)(sbyte)theOp.ValueBytes[0]; numBytes = 4; break; case OpCodes.Ldc_I8: iValue = Utilities.ReadInt64(theOp.ValueBytes, 0); numBytes = 8; break; case OpCodes.Ldc_R4: fValue = Utilities.ReadFloat32(theOp.ValueBytes, 0); numBytes = 4; isFloat = true; break; case OpCodes.Ldc_R8: fValue = Utilities.ReadFloat64(theOp.ValueBytes, 0); numBytes = 8; isFloat = true; break; } //Stores the bytes to be pushed onto the stack byte[] valueBytes = new byte[0]; if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Float constants not supported yet!"); } else { //Get the bytes for the value valueBytes = BitConverter.GetBytes(iValue); } //If pushing Int64: if (numBytes == 8) { //Push the high-bits as a dword //Start the push (0x indicates what follows is a hex number) string valueToPush = "0x"; //High bits //Process bits in reverse order i.e. highest bit first for (int i = numBytes - 1; i > 3; i--) { valueToPush += valueBytes[i].ToString("X2"); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = valueToPush }); //Then push the low-bits as a dword //See above valueToPush = "0x"; //Low bits for (int i = numBytes - 4 - 1; i > -1; i--) { valueToPush += valueBytes[i].ToString("X2"); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = valueToPush }); } else { //See above string valueToPush = "0x"; for (int i = numBytes - 1; i > -1; i--) { valueToPush += valueBytes[i].ToString("X2"); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = valueToPush }); } //Push the constant onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = numBytes, isFloat = isFloat, isGCManaged = false, isValue = true }); }
/// <summary> /// See base class documentation. /// <para>To Do's:</para> /// <list type="bullet"> /// <item> /// <term>To do</term> /// <description>Implement loading 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.NotSupportedException"> /// Thrown when loading 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 load. /// </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.Ldarg: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarg_0: index = 0; break; case OpCodes.Ldarg_1: index = 1; break; case OpCodes.Ldarg_2: index = 2; break; case OpCodes.Ldarg_3: index = 3; break; case OpCodes.Ldarg_S: index = (Int16)theOp.ValueBytes[0]; break; case OpCodes.Ldarga: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarga_S: index = (Int16)theOp.ValueBytes[0]; break; } Types.VariableInfo argInfo = conversionState.Input.TheMethodInfo.ArgumentInfos[index]; if (Utilities.IsFloat(argInfo.TheTypeInfo.UnderlyingType)) { //SUPPORT - floats throw new NotSupportedException("Float arguments not supported yet!"); } //Used to store the number of bytes to add to EBP to get to the arg int BytesOffsetFromEBP = argInfo.Offset; if ((OpCodes)theOp.opCode.Value == OpCodes.Ldarga || (OpCodes)theOp.opCode.Value == OpCodes.Ldarga_S) { //Push the address of the argument onto the stack conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$fp", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); conversionState.Append(new ASMOps.Add() { Src1 = "$t2", Src2 = BytesOffsetFromEBP.ToString(), Dest = "$t2" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); //Push the address onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 4, isFloat = false, isGCManaged = false, isValue = false }); } else { //Push the argument onto the stack Types.TypeInfo paramTypeInfo = argInfo.TheTypeInfo; int bytesForArg = paramTypeInfo.SizeOnStackInBytes; if (bytesForArg % 4 != 0) { throw new ArgumentException("Cannot load arg! Don't understand byte size of the arg! Size:" + bytesForArg); } while (bytesForArg > 0) { bytesForArg -= 4; conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (BytesOffsetFromEBP + bytesForArg).ToString() + "($fp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } //Push the arg onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = paramTypeInfo.SizeOnStackInBytes, isFloat = false, isGCManaged = paramTypeInfo.IsGCManaged, isValue = paramTypeInfo.IsValueType }); } }
/// <summary> /// See base class documentation. /// </summary> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if attempt to add a floating point number since floats are not supported yet. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either stack argument is < 4 bytes in size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop the operands from our stack in reverse order //i.e. second operand was pushed last so comes off the //top of the stack first //Pop item B - one of the items to add StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); //Pop item A - the other item to add StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); //If either item item is < 4 bytes then we have a stack error. if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } //If either item is floating point, we must use floating point conversions //and floating point arithmetic else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats // - We need to convert items to float if necessary // - Then use floating point arithmetic // - Then push the result onto the stack and mark it as float // Note: Check but I think floating point arithmetic is done using // XMM registers and their specific ops. throw new NotSupportedException("Add floats is unsupported!"); } else { //If both items are Int32s (or UInt32s - it is irrelevant) //Note: IL handles type conversions using other ops if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Add the two conversionState.Append(new ASMOps.Add() { Src1 = "$t0", Src2 = "$t1", Dest = "$t1" }); //Push the result onto the stack conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t1" }); //Push the result onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } //Invalid if the operands are of different sizes. //Note: This usually occurs when a previous IL op failed to process properly. else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the same size."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B to $t2:$t1 //Pop low bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop high bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); //Pop item A to $t3:$t0 //Pop low bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Pop high bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); //Add $t2:$t1 to $t3:$t0 //Add low bits conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = "$t0", Dest = "$t4", Unsigned = true }); //Add carry bit to $t5 conversionState.Append(new ASMOps.Sltu() { Src1 = "$t4", Src2 = "$t1", Dest = "$t5" }); //Add high bits including any carry from //when low bits were added conversionState.Append(new ASMOps.Add() { Src1 = "$t5", Src2 = "$t3", Dest = "$t5", Unsigned = true }); conversionState.Append(new ASMOps.Add() { Src1 = "$t5", Src2 = "$t2", Dest = "$t3", Unsigned = true }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t4", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); //Push the result //Push high bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); //Push low bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); //Push the result onto our stack 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 constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { Type elementType = null; Types.TypeInfo elemTypeInfo = null; //bool pushValue = true; int sizeOnHeap = 4; int sizeOnStack = 4; bool isFloat = false; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Stelem: { //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 elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); elemTypeInfo = conversionState.TheILLibrary.GetTypeInfo(elementType); sizeOnStack = elemTypeInfo.SizeOnStackInBytes; sizeOnHeap = elemTypeInfo.IsValueType ? elemTypeInfo.SizeOnHeapInBytes : elemTypeInfo.SizeOnStackInBytes; } break; case OpCodes.Stelem_R4: case OpCodes.Stelem_R8: //TODO - Add more StElem op variants support throw new NotSupportedException("Stelem op variant not supported yet!"); case OpCodes.Stelem_I1: sizeOnHeap = 1; elementType = typeof(sbyte); break; case OpCodes.Stelem_I2: sizeOnHeap = 2; elementType = typeof(Int16); break; case OpCodes.Stelem_Ref: elementType = null; break; case OpCodes.Stelem_I4: elementType = typeof(Int32); break; case OpCodes.Stelem_I8: sizeOnHeap = 8; sizeOnStack = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("StElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Pop the value from the stack into the element //Stack setup upon entering this op: (top-most downwards) // 0. Value to store (dword or 2 dwords) // 1. Index of element to get as Int32 (dword) // 2. Array object reference as address (dword) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 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 // 1.1. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (sizeOnStack + 4) + "]", 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 = "Continue1" }); // 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 = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into EAX // 2.2. Move element type ref from array object into EBX // 2.3. Compare EAX to EBX // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into EAX //if (elementType != null) //{ // result.AppendLine(string.Format("mov EAX, {0}", conversionState.GetTypeIdString(conversionState.GetTypeID(elementType)))); //} //else //{ // //Should be the same for all classes since they are (indirectly) derived from ObjectWithType // int typeOffset = conversionState.GetFieldOffset(arrayDBType, "_Type"); // // - Move value (which is a ref) into EAX // GlobalMethods.CheckAddrFromRegister(conversionState, "ESP", 0); // result.AppendLine("mov EAX, [ESP]"); // // - Move value type ref (from value (ref)) into EAX // GlobalMethods.CheckAddrFromRegister(conversionState, "EAX", typeOffset); // result.AppendLine(string.Format("mov EAX, [EAX+{0}]", typeOffset)); //} //// 2.2. Move element type ref from array object into EBX //// - Move array ref into EBX //GlobalMethods.CheckAddrFromRegister(conversionState, "ESP", sizeToPop == 8 ? 12 : 8); //result.AppendLine(string.Format("mov EBX, [ESP+{0}]", sizeToPop == 8 ? 12 : 8)); //// - Move elemType ref ([EBX+offset]) into EBX int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; //GlobalMethods.CheckAddrFromRegister(conversionState, "EBX", elemTypeOffset); //result.AppendLine(string.Format("mov EBX, [EBX+{0}]", elemTypeOffset)); //// 2.3. Compare EAX to EBX //result.AppendLine("cmp EAX, EBX"); //// 2.4. If the same, jump to continue execution further down //result.AppendLine("je " + ContinueExecutionLabel2); //// 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //result.AppendLine(string.Format("call {0}", conversionState.GetMethodID(conversionState.ThrowArrayTypeMismatchExceptionMethod))); //result.AppendLine(ContinueExecutionLabel2 + ":"); // 3. Check index to get is > -1 and < array length // 3.1. Move index into EAX // 3.2. Move array length into EBX // 3.2. Compare EAX to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare EAX to EBX // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + sizeOnStack + "]", Dest = "EAX" }); // 3.2. Move array length into ECX // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (sizeOnStack + 4) + "]", Dest = "EBX" }); // - Move length value ([EBX+offset]) into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EBX+" + lengthOffset.ToString() + "]", Dest = "EBX" }); // 3.2. Compare EAX to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare EAX to EBX conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "EBX" }); // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2" }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Move index into EDX // 4.2. Move array ref into EAX // 4.3. Move element type ref (from array ref) into EAX // 4.4. Push EAX // 4.5. Move IsValueType (from element ref type) into EAX // 4.6. If IsValueType, continue to 4.7., else goto 4.10. // 4.7. Pop EAX // 4.8. Move Size (from element type ref) into EAX // 4.9. Skip over 4.9. and 4.10. // 4.10. Pop EAX // 4.11. Move StackSize (from element type ref) into EAX // 4.12. Mulitply EAX by EDX (index by element size) // 4.13. Move array ref into EDX // 4.14. Add enough to go past Kernel.FOS_System.Array fields // 4.15. Add EAX and EBX (array ref + fields + (index * element size)) // 4.1. Move index into EDX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + sizeOnStack + "]", Dest = "EDX" }); // 4.2. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (sizeOnStack + 4) + "]", Dest = "EAX" }); // 4.3. Move element type ref (from array ref) into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + elemTypeOffset.ToString() + "]", Dest = "EAX" }); // 4.4. Push EAX conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); // 4.5. Move IsValueType (from element ref type) into EAX int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[EAX+" + isValueTypeOffset.ToString() + "]", Dest = "AL" }); // 4.6. If IsValueType, continue to 4.7., else goto 4.9. conversionState.Append(new ASMOps.Test() { Arg1 = "EAX", Arg2 = "1" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "Continue4_1" }); // 4.7. Pop EAX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); // 4.8. Move Size (from element type ref) into EAX int sizeOffset = conversionState.GetTypeFieldOffset("Size"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + sizeOffset.ToString() + "]", Dest = "EAX" }); // 4.9. Skip over 4.9. and 4.10. conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.10. Pop EAX conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); // 4.11. Move StackSize (from element type ref) into EAX int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + stackSizeOffset.ToString() + "]", Dest = "EAX" }); // 4.12. Mulitply EAX by EDX (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Arg = "EDX" }); // 4.13. Move array ref into EDX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "EDX", Src = "[ESP+" + (sizeOnStack + 4) + "]" }); // 4.14. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src = allFieldsOffset.ToString(), Dest = "EDX" }); // 4.15. Add EAX and EDX (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src = "EDX", Dest = "EAX" }); // 5. Pop the element from the stack to array // 5.1. Pop value bytes from stack to array // 5.2. Add 8 to ESP to remove Index and Array ref for (int i = 0; i < sizeOnStack; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); switch (sizeOnHeap) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "CL", Dest = "[EAX+" + i + "]" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "CX", Dest = "[EAX+" + i + "]" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "CL", Dest = "[EAX+" + i + "]" }); conversionState.Append(new ASMOps.Shr() { Src = "16", Dest = "ECX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "CX", Dest = "[EAX+" + (i + 1) + "]" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "ECX", Dest = "[EAX+" + i + "]" }); break; } sizeOnHeap -= 4; } // 5.2. Add 8 to ESP to remove Index and Array ref conversionState.Append(new ASMOps.Add() { Src = "8", Dest = "ESP" }); // 5.2. Pop index, array ref and value from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); 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 if branch test operand value is a floating point value. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //This will store the offset from the current next op's position //to the IL op to jump to. int ILOffset = 0; //This will store the jump operation - by default, the basic jump op ASMOps.JmpOp jumpOp = ASMOps.JmpOp.Jump; bool UnsignedTest = false; ASMOps.JmpOp inverseJumpOp = ASMOps.JmpOp.None; bool isNegativeTest = false; //The value for the jump op to test against - currently always "0" since on jnz and jz ops are used. string testVal = "0"; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Br: //Load the IL offset as signed Int 32 from the value bytes. ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); break; case OpCodes.Br_S: //Load the IL offset as signed Int 8 from the value bytes. ILOffset = (int)(sbyte)theOp.ValueBytes[0]; break; case OpCodes.Brtrue: //See above. ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-true means we want to do the jump if the operand is not equal to 0 //i.e. not false //Set the jump op to jnz - Jump if Not Zero jumpOp = ASMOps.JmpOp.JumpNotZero; break; case OpCodes.Brtrue_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpNotZero; break; case OpCodes.Brfalse: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-true means we want to do the jump if the operand is equal to 0 //i.e. is false //Set the jump op to jz - Jump if Zero jumpOp = ASMOps.JmpOp.JumpZero; break; case OpCodes.Brfalse_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpZero; break; case OpCodes.Beq: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-equal means we want to do the jump if the operand is equal to the other operand //i.e. A == B //Set the jump op to je - Jump if equal jumpOp = ASMOps.JmpOp.JumpEqual; inverseJumpOp = ASMOps.JmpOp.JumpNotEqual; break; case OpCodes.Beq_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpEqual; inverseJumpOp = ASMOps.JmpOp.JumpNotEqual; break; case OpCodes.Bne_Un: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-equal means we want to do the jump if the operand is equal to the other operand //i.e. A == B //Set the jump op to je - Jump if not equal jumpOp = ASMOps.JmpOp.JumpNotEqual; isNegativeTest = true; break; case OpCodes.Bne_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpNotEqual; isNegativeTest = true; break; case OpCodes.Bge: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-greater-than-or-equal means we want to do the jump if the operand is greater than equal to //the other operand //i.e. A >= B //Set the jump op to jge - Jump if greater than or equal jumpOp = ASMOps.JmpOp.JumpGreaterThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpLessThan; break; case OpCodes.Bge_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpGreaterThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpLessThan; break; case OpCodes.Bge_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpGreaterThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpLessThan; break; case OpCodes.Bge_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpGreaterThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpLessThan; break; case OpCodes.Ble: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-less-than-or-equal means we want to do the jump if the operand is less than equal to //the other operand //i.e. A <= B //Set the jump op to jle - Jump if less than or equal jumpOp = ASMOps.JmpOp.JumpLessThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpGreaterThan; break; case OpCodes.Ble_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpLessThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpGreaterThan; break; case OpCodes.Ble_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpLessThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpGreaterThan; break; case OpCodes.Ble_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpLessThanEqual; inverseJumpOp = ASMOps.JmpOp.JumpGreaterThan; break; case OpCodes.Blt: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-less-than means we want to do the jump if the operand is less than //the other operand //i.e. A < B //Set the jump op to jl - Jump if less than jumpOp = ASMOps.JmpOp.JumpLessThan; isNegativeTest = true; break; case OpCodes.Blt_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpLessThan; isNegativeTest = true; break; case OpCodes.Blt_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpLessThan; isNegativeTest = true; break; case OpCodes.Blt_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpLessThan; isNegativeTest = true; break; case OpCodes.Bgt: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-greater-than means we want to do the jump if the operand is greater than //the other operand //i.e. A > B //Set the jump op to jg - Jump if greater than jumpOp = ASMOps.JmpOp.JumpGreaterThan; isNegativeTest = true; break; case OpCodes.Bgt_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above jumpOp = ASMOps.JmpOp.JumpGreaterThan; isNegativeTest = true; break; case OpCodes.Bgt_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpGreaterThan; isNegativeTest = true; break; case OpCodes.Bgt_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above jumpOp = ASMOps.JmpOp.JumpGreaterThan; isNegativeTest = true; break; } if (ILOffset == 0) { //Err..why bother jumping at all if the offset is 0? conversionState.Append(new ASMOps.Comment("No jump insert - pointless 0 distance jump")); } else { //Get the IL number of the next op int startILNum = theOp.NextOffset; //Add the offset to get the IL op num to jump to int ILNumToGoTo = startILNum + ILOffset; //Find the IL op to jump to ILOp opToGoTo = conversionState.Input.At(ILNumToGoTo); int opToGoToPosition = conversionState.PositionOf(opToGoTo); int currOpPosition = conversionState.PositionOf(theOp); //If the jump op is not a straightforward jump i.e. has one or more conditions if (jumpOp == ASMOps.JmpOp.JumpZero || jumpOp == ASMOps.JmpOp.JumpNotZero) { //Pop from our stack the test item to use in the condition StackItem testItem = conversionState.CurrentStackFrame.Stack.Pop(); if (testItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Branch test based on float not supported!"); } //If the test item is Int64 or UInt64 else if (testItem.sizeOnStackInBytes == 8) { //Compare first 32 bits (low bits) //Then (if necessary) compare second 32 bits (high bits) //Pop the low bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Compare the low bits to the test value conversionState.Append(new ASMOps.Cmp() { Arg2 = testVal, Arg1 = "EAX" }); //Pre-emptively pop the high bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //If we are testing for not equal to zero: if (jumpOp == ASMOps.JmpOp.JumpNotZero) { //If the low bits are not zero, do the jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition }); //Otherwise, test if the high bits are not 0 //We use "cmp" not "test" as "cmp" uses +/- test val, "test" uses & with test val. conversionState.Append(new ASMOps.Cmp() { Arg2 = testVal, Arg1 = "EAX" }); //If the high bits are not zero, do the jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition }); } //If we are testing for equal to zero: else if (jumpOp == ASMOps.JmpOp.JumpZero) { //If the low bits are not zero, jump to the end of these test as condition has not been met conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "End" }); //Otherwise, test if the high bits are zero conversionState.Append(new ASMOps.Cmp() { Arg2 = testVal, Arg1 = "EAX" }); //If they are, do the jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition }); //Insert the end label to be jumped to if condition is not met (see above) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); } else { //Check that no extra ops have been added in the switch block above! throw new NotSupportedException("Unsupported 64-bit branch op!"); } } //If the test item is Int32 or UInt32 else if (testItem.sizeOnStackInBytes == 4) { //Pop the test item conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Compare the test item to the test value conversionState.Append(new ASMOps.Cmp() { Arg2 = testVal, Arg1 = "EAX" }); //Do the specified jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition }); } else { throw new InvalidOperationException("Invalid stack operand sizes!"); } } else if (jumpOp == ASMOps.JmpOp.JumpEqual || jumpOp == ASMOps.JmpOp.JumpNotEqual || jumpOp == ASMOps.JmpOp.JumpGreaterThanEqual || jumpOp == ASMOps.JmpOp.JumpLessThanEqual || jumpOp == ASMOps.JmpOp.JumpLessThan || jumpOp == ASMOps.JmpOp.JumpGreaterThan) { //Pop from our stack the test items to use in the condition StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.isFloat || itemB.isFloat) { //SUPPORT - floats throw new NotSupportedException("Branch test based on float not supported!"); } else if (itemA.sizeOnStackInBytes != itemB.sizeOnStackInBytes) { throw new InvalidOperationException("Branch test operands must be same size!"); } else if (itemA.sizeOnStackInBytes == 8) { //Pop the test item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); //Pop the test item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); if (!isNegativeTest) { //Compare test item A high bits to test item B high bits conversionState.Append(new ASMOps.Cmp() { Arg2 = "ECX", Arg1 = "EDX" }); //If they are not equal, abort the testing conversionState.Append(new ASMOps.Jmp() { JumpType = inverseJumpOp, DestILPosition = currOpPosition, Extension = "End", UnsignedTest = UnsignedTest }); //Else the igh bits are equal so test low bits //Compare test item A low bits to test item B low bits conversionState.Append(new ASMOps.Cmp() { Arg2 = "EBX", Arg1 = "EAX" }); //Do the specified jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); //Insert the end label to be jumped to if condition is not met (see above) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); } else { //Compare test item A high bits to test item B high bits conversionState.Append(new ASMOps.Cmp() { Arg2 = "ECX", Arg1 = "EDX" }); //Do the specified jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); //Compare test item A low bits to test item B low bits conversionState.Append(new ASMOps.Cmp() { Arg2 = "EBX", Arg1 = "EAX" }); //Do the specified jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); } } else if (itemA.sizeOnStackInBytes == 4) { //Pop the test item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop the test item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Compare test item A to test item B conversionState.Append(new ASMOps.Cmp() { Arg2 = "EBX", Arg1 = "EAX" }); //Do the specified jump conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); } else { throw new NotSupportedException("Branch test based on supplied stack item sizes not supported!"); } } else { //Do the straightforward jump... conversionState.Append(new ASMOps.Jmp() { JumpType = jumpOp, DestILPosition = opToGoToPosition }); } } }
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> /// <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!"); } 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 = "[" + fieldId + "]" }); } 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 = "[" + fieldId + "]" }); } else if (size == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[" + fieldId + "]" }); } else if (size == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[" + fieldId + "]" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[" + fieldId + "+4]" }); } 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() { Src = (value.sizeOnStackInBytes - size).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 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) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); 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("Divide floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); if ((OpCodes)theOp.opCode.Value == OpCodes.Rem_Un) { //Unsigned extend A to EAX:EDX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EDX" }); //Do the division conversionState.Append(new ASMOps.Div() { Arg = "EBX" }); } else { //Sign extend A to EAX:EDX conversionState.Append(new ASMOps.Cdq()); //Do the division conversionState.Append(new ASMOps.Div() { Arg = "EBX", Signed = true }); } //Result stored in edx conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the 32-32 or 64-64."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //SUPPORT - 64-bit division throw new NotSupportedException("64-bit by 64-bit modulo not 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 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, isValue = itemA.isValue && itemB.isValue }); } 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, isValue = itemA.isValue && itemB.isValue }); } 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, isValue = itemA.isValue && itemB.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) { conversionState.Append(new ASMOps.Ret()); }
/// <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 either of the values to add are floating point. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if the either of the values to add are less than 4 bytes in size /// or if they are of different sizes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop the operands from our stack in reverse order //i.e. second operand was pushed last so comes off the //top of the stack first //Pop item B - one of the items to subtract StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); //Pop item A - the other item to subtract StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); //If either item item is < 4 bytes then we have a stack error. if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } //If either item is floating point, we must use floating point conversions //and floating point arithmetic else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats // - We need to convert items to float if necessary // - Then use floating point arithmetic // - Then push the result onto the stack and mark it as float // Note: Check but I think floating point arithmetic is done using // XMM registers and their specific ops. throw new NotSupportedException("Sub floats is unsupported!"); } else { //If both items are Int32s (or UInt32s - it is irrelevant) //Note: IL handles type conversions using other ops if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Subtract the two conversionState.Append(new ASMOps.Sub() { Src = "EBX", Dest = "EAX" }); //Push the result onto the stack conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); //Push the result onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } //Invalid if the operands are of different sizes. //Note: This usually occurs when a previous IL op failed to process properly. else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the same size."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B to ecx:ebx //Pop low bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop high bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); //Pop item A to edx:eax //Pop low bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Pop high bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); //Sub ecx:ebx from edx:eax //Sub low bits conversionState.Append(new ASMOps.Sub() { Src = "EBX", Dest = "EAX" }); //Sub high bits including any borrow from //when low bits were subtracted conversionState.Append(new ASMOps.Sub() { Src = "ECX", Dest = "EDX", WithBorrow = true }); //Push the result //Push high bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); //Push low bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); //Push the result onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false, isValue = itemA.isValue && itemB.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) { StackItem itemToConvert = conversionState.CurrentStackFrame.Stack.Pop(); int numBytesToConvertTo = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Conv_U: numBytesToConvertTo = 4; break; case OpCodes.Conv_U1: numBytesToConvertTo = 1; break; case OpCodes.Conv_U2: numBytesToConvertTo = 2; break; case OpCodes.Conv_U4: numBytesToConvertTo = 4; break; case OpCodes.Conv_U8: numBytesToConvertTo = 8; break; } int bytesPopped = 0; bool pushEDX = false; switch (numBytesToConvertTo) { case 1: //Convert to UInt8 (byte) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "AX" }); conversionState.Append(new ASMOps.And() { Src = "0x000000FF", Dest = "EAX" }); bytesPopped = 2; break; case 2: //Convert to UInt16 (word) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "AX" }); bytesPopped = 2; break; case 4: //Convert to UInt32 (dword) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); bytesPopped = 4; break; case 8: //Convert to UInt64 if (itemToConvert.sizeOnStackInBytes == 8) { //Result stored in EAX:EDX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); bytesPopped = 8; } else { //Result stored in EAX:EDX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EDX" }); bytesPopped = 4; } pushEDX = true; break; } int bytesDiff = itemToConvert.sizeOnStackInBytes - bytesPopped; if (bytesDiff > 0) { conversionState.Append(new ASMOps.Add() { Src = bytesDiff.ToString(), Dest = "ESP" }); } if (pushEDX) { 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() { sizeOnStackInBytes = (pushEDX ? 8 : 4), isFloat = false, 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> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load indirect //Pop address //Push [address] StackItem addressItem = conversionState.CurrentStackFrame.Stack.Pop(); int bytesToLoad = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldind_U1: case OpCodes.Ldind_I1: bytesToLoad = 1; break; case OpCodes.Ldind_U2: case OpCodes.Ldind_I2: bytesToLoad = 2; break; case OpCodes.Ldind_U4: case OpCodes.Ldind_I4: case OpCodes.Ldind_I: bytesToLoad = 4; break; case OpCodes.Ldind_I8: bytesToLoad = 8; break; case OpCodes.Ldind_Ref: bytesToLoad = Options.AddressSizeInBytes; break; } int currOpPosition = conversionState.PositionOf(theOp); //Pop address conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); if (bytesToLoad != 1) { // Alignment tests conversionState.Append(new ASMOps.And() { Src1 = "$t1", Src2 = "3", Dest = "$t5" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchEqual, Src1 = "$t5", Src2 = "1", DestILPosition = currOpPosition, Extension = "ByteAligned" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchEqual, Src1 = "$t5", Src2 = "2", DestILPosition = currOpPosition, Extension = "HalfwordAligned" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchEqual, Src1 = "$t5", Src2 = "3", DestILPosition = currOpPosition, Extension = "ByteAligned" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "WordAligned" }); } if ((OpCodes)theOp.opCode.Value == OpCodes.Ldind_Ref) { conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ByteAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "3($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 24 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "2($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 16 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "1($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 8 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "HalfwordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "2($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 16 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "WordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); } else { if (bytesToLoad == 1) { conversionState.Append(new ASMOps.Xor() { Src1 = "$t0", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); } else if (bytesToLoad == 2) { conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ByteAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "1($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 8 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "HalfwordAligned" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "WordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); } else if (bytesToLoad == 4) { conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ByteAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "3($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 24 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "2($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 16 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "1($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 8 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "HalfwordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "2($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 16 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "WordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); } else if (bytesToLoad == 8) { conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ByteAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "7($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 24 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "6($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 16 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "4($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 8 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "5($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "3($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 24 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "2($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 16 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "1($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t4", Dest = "$t4", Bits = 8 }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "HalfwordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "6($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 16 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "4($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "2($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Sll() { Src = "$t0", Dest = "$t0", Bits = 16 }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t1)", Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Or() { Src1 = "$t4", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "WordAligned" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); } } conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = bytesToLoad == 8 ? 8 : 4, isFloat = false, 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 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. /// <para>To Do's:</para> /// <list type="bullet"> /// <item> /// <term>To do</term> /// <description>Implement loading 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.NotSupportedException"> /// Thrown when loading 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 load. /// </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.Ldarg: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarg_0: index = 0; break; case OpCodes.Ldarg_1: index = 1; break; case OpCodes.Ldarg_2: index = 2; break; case OpCodes.Ldarg_3: index = 3; break; case OpCodes.Ldarg_S: index = (Int16)theOp.ValueBytes[0]; break; case OpCodes.Ldarga: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarga_S: index = (Int16)theOp.ValueBytes[0]; break; } //Used to store the number of bytes to add to EBP to get to the arg int BytesOffsetFromEBP = 0; //Get all the params for the current method List <Type> allParams = conversionState.Input.TheMethodInfo.UnderlyingInfo.GetParameters().Select(x => x.ParameterType).ToList(); if (!conversionState.Input.TheMethodInfo.IsStatic) { allParams.Insert(0, conversionState.Input.TheMethodInfo.UnderlyingInfo.DeclaringType); } //Check whether the arg we are going to load is float or not if (Utilities.IsFloat(allParams[index])) { //SUPPORT - floats throw new NotSupportedException("Float arguments not supported yet!"); } //For all the parameters pushed on the stack after the param we want for (int i = allParams.Count - 1; i > -1 && i > index; i--) { //Add the param stack size to the EBP offset BytesOffsetFromEBP += conversionState.TheILLibrary.GetTypeInfo(allParams[i]).SizeOnStackInBytes; } //Add 8 for return address and value of EBP (both pushed at start of method call) BytesOffsetFromEBP += 8; //We must check the return value to see if it has a size on the stack //Get the return type Type retType = (conversionState.Input.TheMethodInfo.IsConstructor ? typeof(void) : ((MethodInfo)conversionState.Input.TheMethodInfo.UnderlyingInfo).ReturnType); //Get the size of the return type int retSize = conversionState.TheILLibrary.GetTypeInfo(retType).SizeOnStackInBytes; //Add it to EBP offset BytesOffsetFromEBP += retSize; if ((OpCodes)theOp.opCode.Value == OpCodes.Ldarga || (OpCodes)theOp.opCode.Value == OpCodes.Ldarga_S) { //Push the address of the argument onto the stack conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$fp", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); conversionState.Append(new ASMOps.Add() { Src1 = "$t2", Src2 = BytesOffsetFromEBP.ToString(), Dest = "$t2" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); //Push the address onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 4, isFloat = false, isGCManaged = false }); } else { //Push the argument onto the stack Types.TypeInfo paramTypeInfo = conversionState.TheILLibrary.GetTypeInfo(allParams[index]); int bytesForArg = paramTypeInfo.SizeOnStackInBytes; if (bytesForArg == 4) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = BytesOffsetFromEBP.ToString() + "($fp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (bytesForArg == 8) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (BytesOffsetFromEBP + 4).ToString() + "($fp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = BytesOffsetFromEBP.ToString() + "($fp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else { throw new ArgumentException("Cannot load arg! Don't understand byte size of the arg!"); } //Push the arg onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = bytesForArg, isFloat = false, isGCManaged = paramTypeInfo.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 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!"); } 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 = "[" + fieldId + "]" }); } 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 = "[" + fieldId + "]" }); } 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 = "[" + fieldId + "+" + i + "]" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[" + fieldId + "+" + i + "]" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[" + fieldId + "+" + i + "]" }); conversionState.Append(new ASMOps.Shr() { Src = "16", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[" + fieldId + "+" + (i + 1) + "]" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[" + fieldId + "+" + i + "]" }); break; } } } else { throw new ArgumentOutOfRangeException("Storing static field with unsupported size! Size: " + size.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 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, isValue = itemA.isValue && itemB.isValue }); } 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, isValue = itemA.isValue && itemB.isValue }); } 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, isValue = itemA.isValue && itemB.isValue }); } } }
/// <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; } //Used to store the number of bytes to subtract from $fp to get to the arg int BytesOffsetFromFp = 0; //Get all the params for the current method List <Type> allParams = conversionState.Input.TheMethodInfo.UnderlyingInfo.GetParameters().Select(x => x.ParameterType).ToList(); if (!conversionState.Input.TheMethodInfo.IsStatic) { allParams.Insert(0, conversionState.Input.TheMethodInfo.UnderlyingInfo.DeclaringType); } //Check whether the arg we are going to load is float or not if (Utilities.IsFloat(allParams[index])) { //SUPPORT - floats throw new NotSupportedException("Float arguments not supported yet!"); } //For all the parameters pushed on the stack after the param we want for (int i = allParams.Count - 1; i > -1 && i > index; i--) { //Add the param stack size to the $fp offset BytesOffsetFromFp += conversionState.TheILLibrary.GetTypeInfo(allParams[i]).SizeOnStackInBytes; } //Add 8 for return address and value of $fp (both pushed at start of method call) BytesOffsetFromFp += 8; //We must check the return value to see if it has a size on the stack //Get the return type Type retType = (conversionState.Input.TheMethodInfo.IsConstructor ? typeof(void) : ((MethodInfo)conversionState.Input.TheMethodInfo.UnderlyingInfo).ReturnType); //Get the size of the return type int retSize = conversionState.TheILLibrary.GetTypeInfo(retType).SizeOnStackInBytes; //Add it to $fp offset BytesOffsetFromFp += retSize; //Pop the argument value from the stack int bytesForArg = conversionState.TheILLibrary.GetTypeInfo(allParams[index]).SizeOnStackInBytes; if (bytesForArg == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = BytesOffsetFromFp.ToString() + "($fp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (bytesForArg == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = BytesOffsetFromFp.ToString() + "($fp)", 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 = (BytesOffsetFromFp + 4).ToString() + "($fp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { throw new ArgumentException("Cannot store arg! Don't understand byte size of the arg!"); } //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 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(conversionState.GetThrowNullReferenceExceptionMethodInfo().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) { //Need to do callvirt related stuff to load address of method to call // - Check for invoke of a delegate - if so, treat rather differently from normal callvirt if (typeof(Delegate).IsAssignableFrom(((MethodInfo)methodToCall).DeclaringType)) { //Callvirt to delegate method // - We only support calls to Invoke at the moment if (methodToCall.Name != "Invoke") { throw new NotSupportedException("Callvirt to Delegate method not supported! Method name: " + methodToCall.Name); } int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => conversionState.TheILLibrary.GetTypeInfo(x.ParameterType).SizeOnStackInBytes).Sum(); // - Move into eax address of function to call from stack - delegate reference is function pointer //All the parameters for the method that was called List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); int bytesForParams = allParams.Select(x => conversionState.TheILLibrary.GetTypeInfo(x).SizeOnStackInBytes).Sum(); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + bytesForParams + "]", Dest = "EAX" }); //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, isValue = retTypeInfo.IsValueType }; //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 { for (int i = 0; i < returnItem.sizeOnStackInBytes; i += 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = "EAX" }); //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 // - Initially at least 4 for the delegate (method) ref/pointer int bytesToAdd = 4; //Go through all params that must be removed 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 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, shift it into final position for (int i = 0; i < returnItem.sizeOnStackInBytes; i += 4) { int srcOffset = returnItem.sizeOnStackInBytes - i - 4; int destOffset = bytesToAdd + srcOffset; conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "EAX", Src = "[ESP+" + srcOffset + "]" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "[ESP+" + destOffset + "]", Src = "EAX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); } else { //Normal callvirt // - Get object ref from loaded args // - Check object ref not null // - Get type table entry from object ref // - Get method table from type table entry // - Scan method table for the method we want // - If found, load method address // - Else, check for parent type method table // - If no parent type method table, throw exception // - Else, scan parent type method table string methodIDValueWanted = methodToCallInfo.IDValue.ToString(); int currOpPosition = conversionState.PositionOf(theOp); Types.TypeInfo declaringTypeInfo = conversionState.TheILLibrary.GetTypeInfo(methodToCall.DeclaringType); //DB_Type declaringDBType = DebugDatabase.GetType(conversionState.GetTypeID(methodToCall.DeclaringType)); //Get object ref int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => conversionState.TheILLibrary.GetTypeInfo(x.ParameterType).SizeOnStackInBytes).Sum(); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + bytesForAllParams + "]", Dest = "EAX" }); //Check object ref conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "NotNull" }); 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 = "NotNull" }); //Get type ref int typeOffset = conversionState.TheILLibrary.GetFieldInfo(declaringTypeInfo, "_Type").OffsetInBytes; conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + typeOffset.ToString() + "]", Dest = "EAX" }); //Get method table ref int methodTablePtrOffset = conversionState.GetTypeFieldOffset("MethodTablePtr"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + methodTablePtrOffset.ToString() + "]", Dest = "EAX" }); //Loop through entries conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "LoopMethodTable" }); //Load ID Val for current entry conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX]", Dest = "EBX" }); //Compare to wanted ID value conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = methodIDValueWanted }); //If equal, load method address into EAX conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotEqual, DestILPosition = currOpPosition, Extension = "NotEqual" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+4]", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "Call" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotEqual" }); //Else, compare to 0 to check for end of table conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "EndOfTable" }); //Not 0? Move to next entry then loop again conversionState.Append(new ASMOps.Add() { Src = "8", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "LoopMethodTable" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "EndOfTable" }); //Compare address value to 0 //If not zero, there is a parent method table to check conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+4]", Dest = "EBX" }); conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "NotFound" }); //Load parent method table and loop conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EBX", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "LoopMethodTable" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotFound" }); //Throw exception! 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 = "Call" }); //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, isValue = retTypeInfo.IsValueType }; //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 { for (int i = 0; i < returnItem.sizeOnStackInBytes; i += 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = "EAX" }); //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, shift it into final position for (int i = 0; i < returnItem.sizeOnStackInBytes; i += 4) { int srcOffset = returnItem.sizeOnStackInBytes - i - 4; int destOffset = bytesToAdd + srcOffset; conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "EAX", Src = "[ESP+" + srcOffset + "]" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "[ESP+" + destOffset + "]", Src = "EAX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); } //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) { throw new NotSupportedException("How the hell are we getting callvirts to constructor methods?!"); } }