/// <summary> /// Build the Inline assembly method, how? quite simple just invoke that method /// So, remember we want use parameters of an assembly method via c#, we have to be completely literal /// </summary> /// <param name="aMethod"></param> private void ExecutableMethod(MethodBase aMethod) { ILCompiler.Logger.Write("@Processor", aMethod.FullName(), "Scanning Inline Assembly Method()"); string xMethodLabel = aMethod.FullName(); TryToMakeGlobalSymbol(aMethod); Core.AssemblerCode.Add(new Label(xMethodLabel)); var Attribute = (AssemblyAttribute)aMethod.GetCustomAttribute(typeof(AssemblyAttribute)); var NeedCalliHeader = Attribute.NeedCalliHeader; /* Well we check if we assign any return size than it means we are lazy * and we want compiler to add calli and return code. */ if (NeedCalliHeader) { Core.AssemblerCode.Add(new Push { DestinationReg = Registers.EBP }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }); } /* Do Invoke here */ aMethod.Invoke(null, new object[aMethod.GetParameters().Length]); ILCompiler.Logger.Write("Method Successfully Invoked()"); if (NeedCalliHeader) { byte RetSize = (byte)Math.Max(0, ILHelper.GetArgumentsSize(aMethod) - ILHelper.GetReturnTypeSize(aMethod)); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.ECX, SourceRef = "0x0" }); Core.AssemblerCode.Add(new Leave()); Core.AssemblerCode.Add(new Ret { Address = (byte)RetSize }); } BuildDefinations.Add(aMethod); ILCompiler.Logger.Write("Method Build Done()"); }
public void FlushStringDataTable() { int CurrentLabel = 0; string Content, str; foreach (var xObj in StringTable) { str = xObj.Key; Content = xObj.Value; Encoding xEncoding = Encoding.Unicode; var xBytecount = xEncoding.GetByteCount(str); var xObjectData = new byte[(xBytecount) + 0x10]; // 0xC is object data offset Array.Copy(BitConverter.GetBytes(ILHelper.GetTypeID(typeof(string))), 0, xObjectData, 0, 4); Array.Copy(BitConverter.GetBytes(0x1), 0, xObjectData, 4, 4); Array.Copy(BitConverter.GetBytes(xObjectData.Length), 0, xObjectData, 8, 4); Array.Copy(BitConverter.GetBytes(str.Length), 0, xObjectData, 12, 4); Array.Copy(xEncoding.GetBytes(str), 0, xObjectData, 16, xBytecount); Core.DataMember.Add(new AsmData(Content, xObjectData)); CurrentLabel++; } }
/// <summary> /// Scan the normal method and find inline calls of virtual or real method to add it into queue /// After that Process method and add its assembly to main Array /// </summary> /// <param name="aMethod">The normal mathod =)</param> private void ScanMethod(MethodBase aMethod) { // Just a basic patch to fix Null reference exception var xBody = aMethod.GetMethodBody(); var xAssemblyName = aMethod.DeclaringType.Assembly.GetName().Name; if (RestrictedAssembliesName.Contains(xAssemblyName) && Plugs.ContainsValue(aMethod.FullName())) { return; } if (ILHelper.IsDelegate(aMethod.DeclaringType)) { ProcessDelegate(aMethod); return; } if (xBody == null) // Don't try to build null method { return; } // Tell logger that we are processing a method with given name and declaring type // Well declaring type is necessary because when we have a plugged method than // Its full name is the plugged value so we will not get where the plug is implemented // So declaring type help us to determine that ILCompiler.Logger.Write("@Processor", aMethod.FullName(), "Scanning Method()"); ILCompiler.Logger.Write("Type: " + aMethod.DeclaringType.FullName); ILCompiler.Logger.Write("Assembly: " + xAssemblyName); /* Scan Method for inline virtual or real methods call */ var xParams = aMethod.GetParameters(); var xParamTypes = new Type[xParams.Length]; for (int i = 0; i < xParams.Length; i++) { xParamTypes[i] = xParams[i].ParameterType; QueuedMember.Enqueue(xParamTypes[i]); } bool DynamicMethod = (aMethod.DeclaringType == null); if (!DynamicMethod) { QueuedMember.Enqueue(aMethod.DeclaringType); } if (aMethod is MethodInfo) { QueuedMember.Enqueue(((MethodInfo)aMethod).ReturnType); } if (!DynamicMethod && aMethod.IsVirtual) { #warning Need to implement currently } /* Process method and get out its IL's array */ // @Newlabels: New labels is the branches where we have to assign method // a label for branch/call IL's operations to perform. // we make its array while making the IL's array so its make our task easier List <int> NewLabels = new List <int>(); var OpCodes = aMethod.Process(NewLabels); // Here seems to be going something wrong ILCompiler.Logger.Write("MSIL Codes Loaded... Count::" + OpCodes.Count); string xMethodLabel = aMethod.FullName(); /* Method begin */ Core.AssemblerCode.Add(new Label(xMethodLabel)); TryToMakeGlobalSymbol(aMethod); Core.AssemblerCode.Add(new Comment(Worker.OPTIMIZATION_START_FLAG)); if (aMethod.IsStatic && aMethod is ConstructorInfo) { string aData = "cctor_" + xMethodLabel; Core.InsertData(new AsmData(aData, new byte[] { 0x00 })); Core.AssemblerCode.Add(new Cmp() { DestinationRef = aData, DestinationIndirect = true, SourceRef = "0x0", Size = 8 }); Core.AssemblerCode.Add(new Jmp() { Condition = ConditionalJumpEnum.JE, DestinationRef = Label.PrimaryLabel + ".Load" }); /* Footer of method */ Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.ECX, SourceRef = "0x0" }); Core.AssemblerCode.Add(new Ret()); Core.AssemblerCode.Add(new Label(".Load")); Core.AssemblerCode.Add(new Mov() { DestinationRef = aData, DestinationIndirect = true, SourceRef = "0x1", Size = 8 }); } /* Calli instructions */ Core.AssemblerCode.Add(new Push() { DestinationReg = Registers.EBP }); Core.AssemblerCode.Add(new Mov() { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }); /* Calculate Method Variables Size */ int Size = (from item in xBody.LocalVariables select item.LocalType.SizeOf().Align()).Sum(); if (Size > 0) { // Make a space for local variables Core.AssemblerCode.Add(new Sub { DestinationReg = Registers.ESP, SourceRef = "0x" + Size.Align().ToString("X") }); } ILCompiler.Logger.Write("Listening OpCodes"); /* Exceute IL Codes */ foreach (var Op in OpCodes) { // Check if we need exception to push? var xNeedsExceptionPush = (Op.Ehc != null) && (((Op.Ehc.HandlerOffset > 0 && Op.Ehc.HandlerOffset == Op.Position) || ((Op.Ehc.Flags & ExceptionHandlingClauseOptions.Filter) > 0 && Op.Ehc.FilterOffset > 0 && Op.Ehc.FilterOffset == Op.Position)) && (Op.Ehc.Flags == ExceptionHandlingClauseOptions.Clause)); ILCompiler.Logger.Write(Op.ToString() + "; Stack Count => " + Core.vStack.Count); // Check if current position inside the list of label list, if yes than break label and make a new one if (NewLabels.Contains(Op.Position)) { var xLbl = new Label(ILHelper.GetLabel(aMethod, Op.Position)); if (!Core.AssemblerCode.Contains(xLbl)) { Core.AssemblerCode.Add(xLbl); } } // If catch IL here than push current error so, that catch IL pop and do what it want if (xNeedsExceptionPush) { Core.AssemblerCode.Add(new Push { DestinationRef = "0x0" }); Core.AssemblerCode.Add(new Call(Helper.lblGetException, true)); Core.vStack.Push(4, typeof(Exception)); } // Well this is just to comment whole output Assembly if (!DoOptimization) { Core.AssemblerCode.Add(new Comment(Op.ToString() + "; " + Core.vStack.Count)); } // Check if this IL is in out implementation if (MSIL.ContainsKey(Op.Code)) { // If yes than execute it MSIL[Op.Code].Execute(Op, aMethod); } else { // If it is not implementation than throw error while compilation throw new Exception(Op.ToString() + "; " + xMethodLabel); } #region Queue Inline calls if (Op is OpMethod) { QueuedMember.Enqueue(((OpMethod)Op).Value); } else if (Op is OpType) { QueuedMember.Enqueue(((OpType)Op).Value); } else if (Op is OpField) { QueuedMember.Enqueue(((OpField)Op).Value.DeclaringType); if (((OpField)Op).Value.IsStatic) { QueuedMember.Enqueue(((OpField)Op).Value); } } else if (Op is OpToken) { var x = ((OpToken)Op); if (x.ValueIsType) { QueuedMember.Enqueue(x.ValueType); } if (x.ValueIsField) { QueuedMember.Enqueue(x.ValueField.DeclaringType); if (x.ValueField.IsStatic) { QueuedMember.Enqueue(x.ValueField); } } } #endregion } // End the method and return method, without exception Core.AssemblerCode.Add(new Label(xMethodLabel + ".End")); // We assume that if the ecx is 0x0 then the method is done without any exception // it can be assumed by test instruction followed by conditional jump while calling a function Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.ECX, SourceRef = "0x0" }); Core.AssemblerCode.Add(new Label(xMethodLabel + ".Error")); // Now below code save the return value to EBP varaible // And calculate size int ArgSize = ILHelper.GetArgumentsSize(aMethod); int ReturnSize = ILHelper.GetReturnTypeSize(aMethod); if (ReturnSize > 0) { // For return type Method var xOffset = ILHelper.GetResultCodeOffset(ReturnSize, ArgSize); for (int i = 0; i < ReturnSize / 4; i++) { Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = (int)(xOffset + ((i + 0) * 4)), SourceReg = Registers.EAX }); } } Core.AssemblerCode.Add(new Comment(Worker.OPTIMIAZTION_END_FLAG)); byte RetSize = (byte)Math.Max(0, ILHelper.GetArgumentsSize(aMethod) - ILHelper.GetReturnTypeSize(aMethod)); // Leave this method mean regain original EBP and ESP offset Core.AssemblerCode.Add(new Leave()); // Return to parent method with given stack offset Core.AssemblerCode.Add(new Ret { Address = RetSize }); // Add this method to build definations so we will not build it again BuildDefinations.Add(aMethod); // And log it ILCompiler.Logger.Write("Method Build Done()"); }
private void ProcessExternalMethod(MethodBase aMethod) { ILCompiler.Logger.Write("@Processor", aMethod.FullName(), "Processing External Method"); if (!aMethod.IsStatic) { throw new Exception("Non-static extern fields not supported"); } var aAttributeData = (DllImportAttribute)aMethod.GetCustomAttribute(typeof(DllImportAttribute)); if (aAttributeData == null) { throw new Exception("[DllImport]: Invalid Build"); } string xLibName = aAttributeData.Value; string xMethodLabel = aMethod.FullName(); string xMethodName = aAttributeData.EntryPoint == null ? aMethod.Name : aAttributeData.EntryPoint; int xCalliConvention = (int)aAttributeData.CallingConvention; bool IsAtomixCompiled = (xCalliConvention == (int)aMethod.CallingConvention); var xParms = aMethod.GetParameters(); /* * For now assume normal calli method * - Push Library Name * - Push Function Name * - Call Kernel API * - Jump to function address */ Core.AssemblerCode.Add(new Label(xMethodLabel)); // standard calli header Core.AssemblerCode.Add(new Push { DestinationReg = Registers.EBP }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }); // load and get address of external function Core.AssemblerCode.Add(new Push { DestinationRef = AddStringData(xLibName) }); Core.AssemblerCode.Add(new Push { DestinationRef = AddStringData(xMethodName) }); Core.AssemblerCode.Add(new Call(Helper.lblImportDll, true)); Core.AssemblerCode.Add(new Test { DestinationReg = Registers.ECX, SourceRef = "0x2" }); Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); int ArgSize = ILHelper.GetArgumentsSize(aMethod); int xReturnSize = ILHelper.GetReturnTypeSize(aMethod); int xRetSize = (ArgSize - xReturnSize); #region _CALLI_HEADER_ if (IsAtomixCompiled) { // push the arguments from left to right for (int i = 0; i < xParms.Length; i++) { int xDisplacement = ILHelper.GetArgumentDisplacement(aMethod, i); int xArgSize = aMethod.GetParameters()[i].ParameterType.SizeOf().Align(); for (int j = 0; j < (xArgSize / 4); j++) { Core.AssemblerCode.Add( new Push { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = xDisplacement - (j * 4) }); } } if (xRetSize < 0) { Core.AssemblerCode.Add(new Sub { DestinationReg = Registers.ESP, SourceRef = "0x" + (-xRetSize).ToString("x") }); xRetSize = 0; } } else if (xCalliConvention == (int)CallingConvention.StdCall) { // push arguments to the stack from right to left for (int i = xParms.Length - 1; i >= 0; i--) { int xDisplacement = ILHelper.GetArgumentDisplacement(aMethod, i); int xArgSize = aMethod.GetParameters()[i].ParameterType.SizeOf().Align(); for (int j = 0; j < (xArgSize / 4); j++) { Core.AssemblerCode.Add( new Push { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = xDisplacement - (j * 4) }); } } } #endregion // Call the function Core.AssemblerCode.Add(new Call("EAX")); #region _CALLI_FOOTER_ if (xReturnSize > 0) { var xOffset = ILHelper.GetResultCodeOffset(xReturnSize, ArgSize); if (IsAtomixCompiled) { // For return type Method for (int i = 0; i < xReturnSize / 4; i++) { Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = (xOffset + (i * 4)), SourceReg = Registers.EAX }); } } else if (xCalliConvention == (int)CallingConvention.StdCall) { if (xReturnSize > 8) { throw new Exception("[Extern]: Unsupported Return Size for StdCall"); } Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = xOffset, SourceReg = Registers.EAX }); if (xReturnSize == 8) { Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = (xOffset + 4), SourceReg = Registers.EAX }); } } } #endregion Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.ECX, SourceRef = "0x0" }); Core.AssemblerCode.Add(new Leave()); Core.AssemblerCode.Add(new Ret { Address = (byte)xRetSize }); BuildDefinations.Add(aMethod); }
private void ProcessDelegate(MethodBase xMethod) { var lbl = xMethod.FullName(); var lbl_exception = lbl + ".Error"; var lbl_end = lbl + ".End"; Core.AssemblerCode.Add(new Label(lbl)); // Calli header Core.AssemblerCode.Add(new Push { DestinationReg = Registers.EBP }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }); if (lbl.Contains("ctor")) { // Load Argument ((Ldarg)MSIL[ILCode.Ldarg]).Execute2(0, xMethod); Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EBX }); ((Ldarg)MSIL[ILCode.Ldarg]).Execute2(2, xMethod); // The pointer Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); Core.AssemblerCode.Add(new Add { DestinationReg = Registers.EBX, SourceRef = "0xC" }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBX, DestinationIndirect = true, SourceReg = Registers.EAX }); ((Ldarg)MSIL[ILCode.Ldarg]).Execute2(1, xMethod); // The Object Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); Core.AssemblerCode.Add(new Add { DestinationReg = Registers.EBX, SourceRef = "0x4" }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBX, DestinationIndirect = true, SourceReg = Registers.EAX }); // calli footer Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.ECX, SourceRef = "0x0" }); Core.AssemblerCode.Add(new Leave()); Core.AssemblerCode.Add(new Ret { Address = 0xC }); // Memory location + Object + Intptr } else if (lbl.Contains("Invoke")) { // Load Reference ((Ldarg)MSIL[ILCode.Ldarg]).Execute2(0, xMethod); Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); Core.AssemblerCode.Add(new Add { DestinationReg = Registers.EAX, SourceRef = "0xC" }); // If it is a non static field than get its parent Type memory location (object in constructor) if (!xMethod.IsStatic) { Core.AssemblerCode.Add(new Push { DestinationReg = Registers.EAX, DestinationDisplacement = 0x4, DestinationIndirect = true }); } var xParms = xMethod.GetParameters(); int xSize = ILHelper.GetArgumentsSize(xMethod); // Load arguments to throw int xArgSize; for (ushort i = 1; i <= xParms.Length; i++) { // New Code int xDisplacement = ILHelper.GetArgumentDisplacement(xMethod, i); if (xMethod.IsStatic) { xArgSize = xMethod.GetParameters()[i].ParameterType.SizeOf().Align(); } else { xArgSize = xMethod.GetParameters()[i - 1].ParameterType.SizeOf().Align(); } for (int j = 0; j < (xArgSize / 4); j++) { Core.AssemblerCode.Add( new Push { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = xDisplacement - (j * 4) }); } } // Call the function Core.AssemblerCode.Add(new Call("[EAX]")); // Check for anytype of exception Core.AssemblerCode.Add(new Test { DestinationReg = Registers.ECX, SourceRef = "0x2" }); Core.AssemblerCode.Add(new Jmp { Condition = ConditionalJumpEnum.JNE, DestinationRef = lbl_exception }); // calli footer Core.AssemblerCode.Add(new Label(lbl_end)); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.ECX, SourceRef = "0x0" }); Core.AssemblerCode.Add(new Label(lbl_exception)); int xReturnSize = ILHelper.GetReturnTypeSize(xMethod); if (xReturnSize > 0) { // For return type Method var xOffset = ILHelper.GetResultCodeOffset(xReturnSize, xSize); for (int i = 0; i < xReturnSize / 4; i++) { Core.AssemblerCode.Add(new Pop { DestinationReg = Registers.EAX }); Core.AssemblerCode.Add(new Mov { DestinationReg = Registers.EBP, DestinationIndirect = true, DestinationDisplacement = (int)(xOffset + ((i + 0) * 4)), SourceReg = Registers.EAX }); } } byte xRetSize = (byte)Math.Max(0, xSize - xReturnSize); Core.AssemblerCode.Add(new Leave()); Core.AssemblerCode.Add(new Ret { Address = xRetSize }); // Parameter + Memory } BuildDefinations.Add(xMethod); }