Pregunta

Me gustaría añadir funcionalidad cpuid a mi aplicación de C #. He encontrado rel="nofollow este interesante entrada de blog en línea. Probablemente necesitaré MASM para compilar esto, pero:

  1. ¿Cómo debo comenzar?
  2. sospecho que voy a tener que compilar una DLL para ambos X86 y X64, pero de nuevo, no tiene ni idea de cómo hacer tal cosa (y estoy un poco presionado por el tiempo).

Por lo que cualquier ayuda sería más que bienvenido!

¿Fue útil?

Solución

CPUID es un dolor gigante y se lo recomiendo a no ir por ese camino si puede evitarlo. CPUID resultados son diferentes entre los procesadores Intel y AMD (al menos para las cosas interesantes como hyperthreading y la topología de caché) y no son particularmente estables a través de diferentes versiones del procesador. (I7 de Intel más recientes introducen un nuevo valor CPUID (EAX = 0xb), que sustituye a la información apoyada por CPUID en procesadores anteriores).

Si usted puede salirse con la suya, la mejor opción sería utilizar WMI (ver Win32_Processor ) o GetLogicalProcessorInformation .

Cualquiera de estos será una solución mucho más simple y más manejable si se apoyan en su plataforma (para obtener información sobre el procesador lógico de cualquier manera requiere SP3 WinXP o posterior en el lado del cliente o Windows Server 2008 o posterior en el lado del servidor) .

Si realmente quiere probar suerte con CPUID, lo que yo recomendaría sería la creación de un talón simple que es capaz de ejecutar CPUID y devolver los resultados a código administrado (necesitará diferentes versiones de 32 bits y 64-bit) y ejecutar los que están dentro del contexto de su aplicación administrada. Hago esto mediante la compilación de una aplicación nativa y luego extraer los bytes de instrucción primas de mi método CPUID en una matriz de bytes que puede ser ejecutado desde el código administrado.

Esto debería ayudará a utilizar para el soporte de 32 bits:

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

Otros consejos

Creo que se puede construir un ensamblado CLR nativo empleando la sintaxis ensamblador (__asm) en código C ++.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top