编译X86 / X64的程序集以与C#一起使用

时间:2009-11-03 19:49:49

标签: c# assembly x86-64 masm

我想在我的C#app中添加cpuid功能。我在网上发现了this有趣的博文。我可能需要MASM来编译它,但是:

  1. 我该如何开始?
  2. 我怀疑我必须为X86和X64编译一个dll,但我再也不知道如何处理这样的事情(而且我的时间有点紧张)。
  3. 所以任何帮助都会受到欢迎!

2 个答案:

答案 0 :(得分:2)

CPUID是一个巨大的痛苦,如果你可以避免它,我建议不要走这条路。 Intel ID和AMD处理器之间的CPUID结果不同(至少对于超线程和缓存拓扑等有趣的东西),并且在不同的处理器版本中并不是特别稳定。 (较新的Intel i7处理器引入了新的CPUID值(eax = 0xb),它取代了早期处理器上CPUID支持的信息。)

如果你能逃脱它,最好的办法是使用WMI(见Win32_Processor)或GetLogicalProcessorInformation

如果您的平台支持这些解决方案,这将是一个非常简单且更易于管理的解决方案(无论哪种方式获取逻辑处理器信息,需要在客户端或Windows Server 2008上使用WinXP sp3或更新版本,或者在服务器端更新)

如果你真的想试试你的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;
}

答案 1 :(得分:-1)

我认为您可以使用C ++代码中的内联汇编语法(__asm)构建本机CLR程序集。