2015-03-13 27 views
8

İşlemcim (Intel i7), POPCNT instruction numaralı telefonu destekliyor ve bunu C# uygulamamdan çağırmak istiyorum. Mümkün mü?C# dan CPU komutu nasıl aranır?

Olmadığını bir yerde okuduğuma inanıyorum, ancak JIT, uygun bulduğu takdirde onu çağırır ama böyle bir talimatla değiştirilebilecek hangi işlevi çağırmam gerekir?

Popcount, döngü içinde milyonlarca kez çağrılıyor, bu nedenle mümkünse bu CPU optimizasyonuna sahip olmak isterim.

+3

C# bunun için doğru dil mi? C# gibi dilleri kullandığımızı düşündüm, bu yüzden CPU talimatları hakkında düşünmemize gerek yok. –

+0

Hayır, öyle değil. Bununla birlikte, C# ile çalışmayı tercih ederim. –

+1

Bu soru StackOverFlow'da sorulmuş ve yanıtlanmıştır. [1]: http://stackoverflow.com/questions/6097635/checking-cpu-popcount-from-c-sharp –

cevap

13

Sen ... biz ateşle oynamak ister burada ateşle oynamak istiyorum ve

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

(toplanma bu küçük örnek sadece ben bunun için mükemmel bir rakam düşünüyorum ... 42 dönecektir cevap :-)) hile olmasıdır sonunda

: sen

B yazmak istiyorum asm karşılık gelen opcodes) sen VirtualAlloc kullanmak bilmelisiniz

A) Bir şekilde bellek yürütülebilir

C) bir sayfa yapmak size işlem kodları (kod) http://www.cnblogs.com/netact/archive/2013/01/10/2855448.html den

Tamam alınmıştır

... diğeri sitesinde yazılmıştır olarak

orada kopya ( uint bir hata eksi -> IntPtr dwSize), bu kimse yazılmalıdır (veya en azından ben try... finally kullanmanın IDisposable sınıfında şeyi yerine kapsülleyen ... orijinale kıyasla 1 var)

nasıl
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(); 
       } 
      } 
     } 
    } 
} 
+3

Kopyalamadan sonra “VirtualProtect” i çağırmak daha iyidir, X bitini eklemek ve W'yi kaldırmak için W^X'i zorlamak güvenlik açısından iyi görünüyor. –

+0

@BenVoigt Verbatim'i kod örneğini kopyalamayı tercih ettim ... Ama evet, normalde söylediğiniz gibi yapmak daha iyidir. – xanatos

+1

Heretic onayladı. – IllidanS4