0

C#アプリにcpuid機能を追加したいと思います。この興味深いブログ投稿をオンラインで見つけました。これをコンパイルするにはおそらくMASMが必要ですが:

  1. どのように始めればよいですか?
  2. X86とX64の両方のdllをコンパイルする必要があると思いますが、そのようなことをどのように行うかについての手がかりがありません(そして私は少し時間に追われています)。

だからどんな助けでも大歓迎です!

4

2 に答える 2

2

CPUID は大きな問題であり、回避できるのであれば、その道をたどらないことをお勧めします。CPUID の結果は、Intel プロセッサと AMD プロセッサの間で異なり (少なくともハイパースレッディングやキャッシュ トポロジなどの興味深いものについては)、異なるプロセッサ バージョン間で特に安定しているわけではありません。(新しい Intel i7 プロセッサでは、新しい CPUID 値 (eax=0xb) が導入され、以前のプロセッサで CPUID によってサポートされていた情報に取って代わります)。

それを回避できる場合は、WMI ( Win32_Processorを参照) またはGetLogicalProcessorInformationを使用することをお勧めします。

どちらも、プラットフォームでサポートされている場合、非常にシンプルで管理しやすいソリューションになります (論理プロセッサ情報を取得するには、クライアント側で WinXP sp3 以降、またはサーバー側で Windows Server 2008 以降が必要です)。

本当に CPUID を試してみたい場合は、CPUID を実行して結果をマネージ コードに返すことができる単純なスタブを作成することをお勧めします (32 ビットと 64 ビットでは異なるバージョンが必要になります)。 )、マネージド アプリケーションのコンテキスト内でそれらを実行します。これを行うには、ネイティブ アプリケーションをコンパイルし、CPUID メソッドの生の命令バイトをマネージド コードから実行できるバイト配列に抽出します。

これにより、32 ビットのサポートのみを開始できます。

using System;
using System.Runtime.InteropServices;

static class Program {
  static void Main() {
    //Allocate the executable buffer on a distinct page 
    // rather than just pinning it in place because we
    // need to mark the page as executable.
    // Failing to do this would cause NX-enabled machines 
    // to have access violations attempting to execute.
    IntPtr pExecutableBuffer = VirtualAlloc(
      IntPtr.Zero,
      new IntPtr(CPUID_32.Length),
      AllocationType.MEM_COMMIT | AllocationType.MEM_RESERVE,
      MemoryProtection.PAGE_EXECUTE_READWRITE
    );

    Marshal.Copy(CPUID_32, 0, pExecutableBuffer, CPUID_32.Length);
    CPUID executeHandler = (CPUID)Marshal.GetDelegateForFunctionPointer(
      pExecutableBuffer, typeof(CPUID));
    CPUID_Args args = new CPUID_Args();
    args.eax = 0;
    executeHandler(ref args);
    Console.WriteLine("eax: {0} ebx: {1} ecx: {2} edx: {3}",
      args.eax,
      args.ebx,
      args.ecx,
      args.edx);
    VirtualFree(
      pExecutableBuffer,
      IntPtr.Zero,
      FreeType.MEM_RELEASE);
  }

  [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  delegate void CPUID(ref CPUID_Args args);

  private static readonly byte[] CPUID_32 = new byte[] {
    0x53,          // push ebx 
    0x57,          // push edi 
    0x8B, 0x7C, 0x24, 0x0C, // mov edi,dword ptr [esp+0Ch] 
    0x8B, 0x07,       // mov eax,dword ptr [edi] 
    0x8B, 0x4F, 0x08,    // mov ecx,dword ptr [edi+8] 
    0x0F, 0xA2,       // cpuid      
    0x89, 0x07,       // mov dword ptr [edi],eax 
    0x89, 0x5F, 0x04,    // mov dword ptr [edi+4],ebx 
    0x89, 0x4F, 0x08 ,    // movdword ptr [edi+8],ecx 
    0x89, 0x57, 0x0C ,    // mov dword ptr [edi+0Ch],edx 
    0x5F,          // pop     edi 
    0x5B,          // pop     ebx 
    0xC2, 0x04, 0x00     // ret
    };

  [Flags]
  enum AllocationType {
    MEM_COMMIT = 0x1000,
    MEM_RESERVE = 0x2000,
  }

  [Flags]
  enum MemoryProtection {
    PAGE_EXECUTE_READWRITE = 0x40,
  }

  [Flags]
  enum FreeType {
    MEM_RELEASE = 0x8000
  }

  [DllImport("kernel32.dll")]
  static extern IntPtr VirtualAlloc(
    IntPtr lpAddress,
    IntPtr dwSize,
    AllocationType flAllocationType,
    MemoryProtection flProtect);

  [DllImport("kernel32.dll")]
  [return: MarshalAs(UnmanagedType.Bool)]
  static extern bool VirtualFree(
    IntPtr lpAddress,
    IntPtr dwSize,
    FreeType dwFreeType);
}

[StructLayout(LayoutKind.Sequential)]
struct CPUID_Args {
  public uint eax;
  public uint ebx;
  public uint ecx;
  public uint edx;
}
于 2009-11-03T20:40:26.090 に答える
-1

__asmC++ コードでインライン アセンブラ構文 ( ) を使用するネイティブ CLR アセンブリを構築できると思います。

于 2009-11-03T19:56:38.947 に答える