c# - 如何从 C# 调用 CPU 指令?

标签 c# optimization cpu hammingweight

我的处理器 (Intel i7) 支持 POPCNT 指令,我想从我的 C# 应用程序中调用它。这可能吗?

我相信我在某处读到它不是,但是如果 JIT 发现它可用,它会调用它,但是我必须调用什么函数可以用这样的指令代替?

Popcount 在一个循环中被调用了数百万次,所以如果可能的话,我希望能够进行这种 CPU 优化。

最佳答案

你想玩火,我们这里喜欢玩火...

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());
    }
}

(这个小的汇编示例将简单地返回 42...我认为这是这个答案的完美数字:-))

最后的诀窍是:

A) 你必须知道你要写的asm对应的操作码

B) 你使用 VirtualAlloc 使一页内存可执行

C) 你以某种方式在那里复制你的操作码

(代码取自http://www.cnblogs.com/netact/archive/2013/01/10/2855448.html)

好的...另一个是网站上写的(减去 uint -> IntPtr dwSize 上的错误),这个应该是这样的写的(或者至少它比原来的+1...我会把所有东西都封装在一个IDisposable类中而不是使用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();
                }
            }
        }
    }
}

关于c# - 如何从 C# 调用 CPU 指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29040550/

相关文章:

c# - 使用 C# 从文本文件序列化 Json

c# - 将 List<Point> 存储在字符串中并解析回来的最佳方法

c++ - "as-if"规则到底是什么?

angular - 检查对象列表中任何对象的属性中是否存在值

c# - 以编程方式创建和执行合并复制

C# 将字符串转换为 DateTime

assembly - 优化第 7 代英特尔酷睿视频 RAM 中递增的 ASCII 十进制计数器

c - 用于 CPU 使用的 Linux C API

operating-system - 启动期间是否使用了所有 CPU 内核?

floating-point - CPU中常用的浮点运算有哪些算法?