My processor (Intel i7) supports the POPCNT instruction and I would like to call it from my C# application. Is this possible?
I believe I read somewhere that it isn't, but the JIT will invoke it if it finds it available but what function would I have to call that may be substituted with such an instruction?
Popcount is being called millions of times in a loop so I'd like to be able to have this CPU optimization if possible.
You want to play with fire, and here we like to play with fire...
class Program
{
    const uint PAGE_EXECUTE_READWRITE = 0x40;
    const uint MEM_COMMIT = 0x1000;
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
    private delegate int IntReturner();
    static void Main(string[] args)
    {
        List<byte> bodyBuilder = new List<byte>();
        bodyBuilder.Add(0xb8); // MOV EAX,
        bodyBuilder.AddRange(BitConverter.GetBytes(42)); // 42
        bodyBuilder.Add(0xc3);  // RET
        byte[] body = bodyBuilder.ToArray();
        IntPtr buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        Marshal.Copy(body, 0, buf, body.Length);
        IntReturner ptr = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
        Console.WriteLine(ptr());
    }
}
(this small example of assembly will simply return 42... I think it's the perfect number for this answer :-) )
In the end the trick is that:
A) You must know the opcodes corresponding to the asm you want to write
B) You use VirtualAlloc to make a page of memory executable
C) In some way you copy your opcodes there
(the code was taken from http://www.cnblogs.com/netact/archive/2013/01/10/2855448.html)
Ok... the other one was as written on the site (minus an error on the uint -> IntPtr dwSize), this one is how it should be written (or at least it's a +1 compared to the original... I would encapsulate everything in a IDisposable class instead of using try... finally)
class Program
{
    const uint PAGE_READWRITE = 0x04;
    const uint PAGE_EXECUTE = 0x10;
    const uint MEM_COMMIT = 0x1000;
    const uint MEM_RELEASE = 0x8000;
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
    private delegate int IntReturner();
    static void Main(string[] args)
    {
        List<byte> bodyBuilder = new List<byte>();
        bodyBuilder.Add(0xb8); // MOV EAX,
        bodyBuilder.AddRange(BitConverter.GetBytes(42)); // 42
        bodyBuilder.Add(0xc3);  // RET
        byte[] body = bodyBuilder.ToArray();
        IntPtr buf = IntPtr.Zero;
        try
        {
            // We VirtualAlloc body.Length bytes, with R/W access
            // Note that from what I've read, MEM_RESERVE is useless
            // if the first parameter is IntPtr.Zero
            buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_READWRITE);
            if (buf == IntPtr.Zero)
            {
                throw new Win32Exception();
            }
            // Copy our instructions in the buf
            Marshal.Copy(body, 0, buf, body.Length);
            // Change the access of the allocated memory from R/W to Execute
            uint oldProtection;
            bool result = VirtualProtect(buf, (IntPtr)body.Length, PAGE_EXECUTE, out oldProtection);
            if (!result)
            {
                throw new Win32Exception();
            }
            // Create a delegate to the "function"
            // Sadly we can't use Funct<int>
            var fun = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
            Console.WriteLine(fun());
        }
        finally
        {
            if (buf != IntPtr.Zero)
            {
                // Free the allocated memory
                bool result = VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
                if (!result)
                {
                    throw new Win32Exception();
                }
            }
        }
    }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With