我想爲我的C#應用程序添加cpuid功能。我在網上發現this有趣的博客文章。我可能需要MASM來編譯這個,但是:編譯用於C#的X86/X64程序集#
- 我該如何啓動?
- 我懷疑我將不得不爲X86和X64編譯一個dll,但我不知道如何去處理這樣的事情(而且我有點時間緊張)。
所以,任何幫助將超過歡迎!
我想爲我的C#應用程序添加cpuid功能。我在網上發現this有趣的博客文章。我可能需要MASM來編譯這個,但是:編譯用於C#的X86/X64程序集#
所以,任何幫助將超過歡迎!
CPUID是一個巨大的痛苦,我會建議不要沿着這條路走下去,如果你能避免它。英特爾和AMD處理器之間的CPUID結果不同(至少對於超線程和緩存拓撲結構等有趣的內容),並且在不同處理器版本之間並不是特別穩定。 (較新的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;
}
我想你可以在C++代碼中使用內聯彙編語法(__asm
)構建一個本地CLR程序集。
我似乎記得這在X64模式下無法正常工作。 – Kris 2009-11-03 20:16:13
哦,我在Windows上與C#/ C++混淆了一段時間,這肯定是win32。 – 2009-11-03 20:39:48
現在這是一個有用的答案:) 你是第一個提到這可能是32位和64位之間的真正區別。你能否就這些差異在哪裏提供一些額外的指導? 您的一般策略似乎與此相符: http://devpinoy.org/blogs/cvega/archive/2006/04/07/2658.aspx 可能您有任何想法,我可以如何正確編譯位模式? – Kris 2009-11-03 20:48:20
我剛剛意識到,您的答案中的代碼可能只能用於32位,因爲X64位編譯不允許內聯asm? – Kris 2009-11-03 20:51:13
該代碼可以在運行32位操作系統的64位機器上運行(這可能不是您要求的)。真正支持64位更復雜......首先,您必須決定是否支持IA64或僅支持x64/AMD64 /無論您想調用它。然後,您需要一個不同版本的字節數組(稱爲CPUID_64)和代碼,以確保在您要調用CPUID時執行正確版本的字節數組。然而,這個例子本身並沒有使用「內聯彙編」。 x86正在動態加載和執行,它不是二進制文件的可執行部分。 – StarPacker 2009-11-03 20:57:22