C++ 损坏的CPUID品牌字符串?

C++ 损坏的CPUID品牌字符串?,c++,assembly,x86-64,masm,uefi,C++,Assembly,X86 64,Masm,Uefi,我正在使用CPUID指令打印操作系统中有关CPU的一些信息 读取和打印供应商字符串(GenuineIntel)效果很好,但读取品牌字符串会给我带来一些奇怪的字符串 ok cpu-info <= Run command CPU Vendor name: GenuineIntel <= Vendor string is good CPU Brand: D: l(R) Core(TMD: CPU MD: <= What..? ok 但我得到的是: D: l

我正在使用CPUID指令打印操作系统中有关CPU的一些信息

读取和打印供应商字符串(GenuineIntel)效果很好,但读取品牌字符串会给我带来一些奇怪的字符串

ok cpu-info <= Run command
CPU Vendor name: GenuineIntel <= Vendor string is good
CPU Brand: D:  l(R)  Core(TMD:   CPU       MD:  <= What..?
ok
但我得到的是:

 D:  l(R)  Core(TMD:   CPU       MD:
C++代码:

            char vendorString[13] = { 0, };
            Dword eax, ebx, ecx, edx;
            ACpuid(0, &eax, &ebx, &ecx, &edx);
            *((Dword*)vendorString) = ebx;
            *((Dword*)vendorString + 1) = edx;
            *((Dword*)vendorString + 2) = ecx;
            Console::Output.Write(L"CPU vendor name: ");
            for (int i = 0; i < 13; i++) {
                Console::Output.Write((wchar_t)(vendorString[i]));
            }
            Console::Output.WriteLine();

            char brandString[48] = { 0, };
            ACpuid(0x80000002, &eax, &ebx, &ecx, &edx);
            *((Dword*)brandString) = eax;
            *((Dword*)brandString + 1) = ebx;
            *((Dword*)brandString + 2) = ecx;
            *((Dword*)brandString + 3) = edx;
            ACpuid(0x80000003, &eax, &ebx, &ecx, &edx);
            *((Dword*)brandString + 4) = eax;
            *((Dword*)brandString + 5) = ebx;
            *((Dword*)brandString + 6) = ecx;
            *((Dword*)brandString + 7) = edx;
            ACpuid(0x80000004, &eax, &ebx, &ecx, &edx);
            *((Dword*)brandString + 8) = eax;
            *((Dword*)brandString + 9) = ebx;
            *((Dword*)brandString + 10) = ecx;
            *((Dword*)brandString + 11) = edx;
            Console::Output.Write(L"CPU brand: ");
            for (int i = 0; i < 48; i++) {
                Console::Output.Write((wchar_t) brandString[i]);
            }
            Console::Output.WriteLine();

我同意Ross Ridge的观点,你应该使用编译器的内在特性。至于为什么您的代码可能无法正常工作,有一些bug会导致问题


销毁RAX、RBX、RCX和RDX的内容,但在代码中执行此操作:

cpuid
mov [ rdx ], eax
在执行eax时,
mov[RDX],RDX已被销毁,导致RDX中的指针无效。在使用
CPUID
指令之前,需要将RDX移动到另一个寄存器

根据,这些是需要由调用方保存的易失性寄存器:

寄存器RAX、RCX、RDX、R8、R9、R10、R11被认为是易失性的,并且在函数调用时必须被视为已销毁(除非通过分析(如整个程序优化)可以证明安全性)

这些是非易失性的,需要被调用方保存:

寄存器RBX、RBP、RDI、RSI、RSP、R12、R13、R14和R15被认为是非易失性的,必须由使用它们的函数保存和恢复

我们可以使用R10(易失性寄存器)临时存储RDX。与在代码中使用RSI不同,我们可以重用R10来更新
pEdx
处的值。如果我们不使用RSI,就不需要保留它。CPUID确实破坏了RBX,而且RBX是非易失性的,所以我们需要保存它。RAX是易变的,所以我们不需要保存它


在代码中有以下行:

mov [ rsi ], rdx
RSI是调用者提供的内存地址(
pEdx
),用于将值存储在EDX中。您拥有的代码会将8字节寄存器RDX的内容移动到预期为4字节DWORD的内存位置。这可能会在调用者中丢弃数据。这真的应该是:

mov [ rsi ], edx

考虑到以上所有因素,我们可以通过以下方式对
ACpuid
例程进行编码:

option casemap:none
.code

;Cpuid command
;ACpuid(Type, pEax, pEbx, pEcx, pEdx)
ACpuid Proc
    ;Type => Rcx
    ;pEax => Rdx
    ;pEbx => R8
    ;pEcx => R9
    ;pEdx => [ rbp + 48 ] ?
    push rbp
    mov rbp, rsp
    push rbx         ; Preserve RBX (destroyed by CPUID)

    mov r10, rdx     ; Save RDX before CPUID
    mov rax, rcx
    cpuid
    mov [ r10 ], eax
    mov [ r8 ], ebx
    mov [ r9 ], ecx
    mov r10, [ rbp + 48 ]
    mov [ r10 ], edx ; Last parameter is pointer to 32-bit DWORD, 
                     ;  Move EDX to the memory location, not RDX

    pop rbx
    pop rbp
    ret
ACpuid Endp

end

愚蠢的问题。你的程序是否具有完全权限?你是指C++还是C++?@Console是EFI控制台的名称空间。(Console::Output是Console Output)不是C#中的Console类。啊,好吧,我只是想确保使用
\uuuCPUID
内在函数而不是汇编函数:我还建议更改函数签名,只向结构传递一个指针!这样两端的代码就更简单了。(但仍然比使用像
\uu cpuid()
)这样的内置编译器复杂得多。)@PeterCordes:我有意不改变他的代码结构。我正在确定导致他的代码无法正常运行的主要问题。更好的解决办法在我答案的第一行。使用u_cpuid编译器内部代码,不需要汇编程序例程。
mov [ rsi ], edx
option casemap:none
.code

;Cpuid command
;ACpuid(Type, pEax, pEbx, pEcx, pEdx)
ACpuid Proc
    ;Type => Rcx
    ;pEax => Rdx
    ;pEbx => R8
    ;pEcx => R9
    ;pEdx => [ rbp + 48 ] ?
    push rbp
    mov rbp, rsp
    push rbx         ; Preserve RBX (destroyed by CPUID)

    mov r10, rdx     ; Save RDX before CPUID
    mov rax, rcx
    cpuid
    mov [ r10 ], eax
    mov [ r8 ], ebx
    mov [ r9 ], ecx
    mov r10, [ rbp + 48 ]
    mov [ r10 ], edx ; Last parameter is pointer to 32-bit DWORD, 
                     ;  Move EDX to the memory location, not RDX

    pop rbx
    pop rbp
    ret
ACpuid Endp

end