Компиляция сборки для X86/X64 для использования с C#

StackOverflow https://stackoverflow.com/questions/1669723

  •  13-09-2019
  •  | 
  •  

Вопрос

Я хотел бы добавить функциональность cpuid в свое приложение C#.я нашел этот интересный пост в блоге в Интернете.Мне, вероятно, понадобится MASM для компиляции, но:

  1. Как мне начать?
  2. Я подозреваю, что мне придется скомпилировать dll как для X86, так и для X64, но, опять же, я понятия не имею, как это сделать (и у меня немного поджимает время).

Так что любая помощь будет более чем желательна!

Это было полезно?

Решение

CPUID — это огромная проблема, и я бы советовал не идти по этому пути, если вы можете его избежать.Результаты CPUID различаются для процессоров Intel и AMD (по крайней мере, для таких интересных вещей, как гиперпоточность и топология кэша) и не особенно стабильны для разных версий процессоров.(В более новых процессорах Intel i7 появилось новое значение CPUID (eax=0xb), которое заменяет информацию, поддерживаемую CPUID на более ранних процессорах).

Если вам это сходит с рук, лучше всего использовать WMI (см. Win32_Процессор) или 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;
}

Другие советы

Я думаю, вы можете создать собственную сборку CLR, используя встроенный синтаксис ассемблера (__asm) в коде C++.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top