Generally, executing native assembly in C# is bad because you lose all the benefits of the managed world. In the cases where it is impossible to perform something in C#, it is better to make a C++ DLL. That said, the new method Marshal.GetDelegateForFunctionPointer() in the .NET Framework v2.0 opens up the possibility for dynamically writing and executing assembly code. Consider the following basic C function:
int __declspec(noinline) __stdcall MyAdd(int x, int y) { return x + y; }
The C compiler will compile the code into assembly. Though the code which gets compiled may vary from compiler to platform, for x86 it will usually have this basic form:
Instruction Code Bytes Comment ------------------------------------------------------------------------------ mov eax,dword ptr [esp+8] ' 8B 44 24 08 Load the x into eax mov ecx,dword ptr [esp+4] ' 8B 4C 24 04 Load the y into ecx add eax,ecx ' 03 C1 Add eax and ecx, result goes into eax ret 8 ' C2 08 00 Pop x and y off the stack, return eax
The instructions listed are disassembly copied from the VC++ debugger. The code bytes are what actually executes. The idea is to take those code bytes, write them into a native buffer, acquire a delegate for that buffer, and finally execute the delegate. Here is sample code to run these code bytes from C#:
using System; using System.Runtime.InteropServices; class Program { private delegate Int32 MyAdd(Int32 x, Int32 y); private static void Main() { // A simple Add function Byte[] myAddNativeCodeBytes = new Byte[] { 0x8B, 0x44, 0x24, 0x08, // mov eax,dword ptr [esp+8] 0x8B, 0x4C, 0x24, 0x04, // mov ecx,dword ptr [esp+4] 0x03, 0xC1, // add eax,ecx 0xC2, 0x08, 0x00 // ret 8 }; // We need to push the code bytes into a native buffer IntPtr myAddNativeCodeBytesPtr = IntPtr.Zero; try { // Allocate the native buffer myAddNativeCodeBytesPtr = Marshal.AllocCoTaskMem(myAddNativeCodeBytes.Length); // Push the code bytes over Marshal.Copy(myAddNativeCodeBytes, 0, myAddNativeCodeBytesPtr, myAddNativeCodeBytes.Length); // Get a function pointer for the native code bytes MyAdd myAdd = (MyAdd)Marshal.GetDelegateForFunctionPointer( myAddNativeCodeBytesPtr, typeof(MyAdd)); // Call the native code bytes Int32 result = myAdd(4, 5); // Did it work? Console.WriteLine("Result: {0}", result); } finally { // Free the native buffer if (myAddNativeCodeBytesPtr != IntPtr.Zero) { Marshal.FreeCoTaskMem(myAddNativeCodeBytesPtr); myAddNativeCodeBytesPtr = IntPtr.Zero; } } } }
In this sample I just used Marshal.AllocCoTaskMem(), but one should actually P/Invoke VirtualAllocEx and VirtualProtectEx to ensure the page where the code exists has PAGE_EXECUTE access. Additionally the above sample is targetted to my personal x86 machine, and will not run on x64 or any other platform for that matter.