Компиляция сборки для X86/X64 для использования с C#
Вопрос
Я хотел бы добавить функциональность cpuid в свое приложение C#.я нашел этот интересный пост в блоге в Интернете.Мне, вероятно, понадобится MASM для компиляции, но:
- Как мне начать?
- Я подозреваю, что мне придется скомпилировать 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++.