2012-08-31 34 views
4

我想使用cpuid指令來識別Intel CPU的功能。我在Kernel.framework中找到了cpuid.h頭文件,所以我將Kernel.framework添加到了我的項目中,並在我的源文件中包含了<Kernel/i386/cpuid.h>。那生產如何在Mac框架中調用cpuid指令?

kern/kern_types.h: No such file or directory 

我不明白。但是我認爲我想使用的功能do_cpuid是內聯定義的,所以我嘗試將其複製到我的源代碼中。

static inline void 
do_cpuid(uint32_t selector, uint32_t *data) 
{ 
    asm("cpuid" 
     : "=a" (data[0]), 
      "=b" (data[1]), 
      "=c" (data[2]), 
      "=d" (data[3]) 
     : "a"(selector)); 
} 

這給了我的錯誤:

error: can't find a register in class 'BREG' while reloading 'asm' 
error: 'asm' operand has impossible constraints 

谷歌搜索的錯誤導致我這樣一個問題:Problem on Mac : "Can't find a register in class BREG while reloading asm"

但是解決這個問題是使用動態無pic選項(編譯設置),Xcode對編譯設置的幫助表示「不適合共享庫(它們需要與位置無關)」。我正在構建一個框架,我認爲這是一個共享庫。那我該如何做這項工作?

回答

0

這非常模糊的錯誤消息:

error: can't find a register in class 'BREG' while reloading 'asm' 
error: 'asm' operand has impossible constraints 

發生因爲是不允許的約束中的一個。在這種情況下,它是EBX。使用-fPIC選項(位置獨立代碼)編譯32位代碼時,將使用EBX寄存器進行重定位。它不能被用作輸出或者看起來像一個破碎的寄存器。

雖然大多數人建議用特殊的編譯器編譯的標誌,該函數可以被重寫以支持X86-64 /IA32PIC通過修改彙編代碼保存EBX寄存器/ 非PIC本身並在恢復之後。這可以用類似的代碼來完成:

#include <inttypes.h> 

static inline void 
do_cpuid(uint32_t selector, uint32_t *data) 
{ 
    __asm__ __volatile__ (
     "xor %%ecx,%%ecx\n\t" 
     "xchg %%ebx, %k[tempreg]\n\t" 
     "cpuid\n\t" 
     "xchg %%ebx, %k[tempreg]\n" 
     : "=a" (data[0]), 
      [tempreg]"=&r" (data[1]), 
      "=c" (data[2]), 
      "=d" (data[3]) 
     : "a"(selector)); 
} 

的顯著變化是值將在可用時返回註冊編譯器選擇。 =&r約束告訴編譯器,它選擇的任何寄存器都不能是任何其他輸入寄存器(我們提前用xchg代碼摧毀了寄存器)。在代碼中,我們使用編譯器選擇的可用寄存器來交換EBX。然後我們將之交換回去。完成時EBX將包含其原始值,並且所選的免費寄存器將包含由CPUID返回的內容。然後彙編程序模板將把該空閒寄存器的內容移動到。

實際上,我們通過允許編譯器選擇一個空閒寄存器來避免了這個問題。編譯器足夠智能,因爲它可能被用於可重定位代碼,所以不要使用EBX。在64位代碼中,EBX不用於重定位,就像使用32位代碼一樣,因此它可以用於使用。

一位精明的觀察者可能已經注意到xor %%ecx,%%ecx。這是我獨立於EBX問題的改變。現在認爲清除ECX是一種很好的做法,因爲如果ECX不爲零,由AMD製造的某些處理器可能會返回陳舊值。如果您僅開發非PPC Mac平臺,則此更改不是必需的,因爲Apple使用的英特爾處理器不具備此類行爲。

一般EBX在32位可重定位/ PIC代碼中是特殊的,這就是爲什麼編譯器最初抱怨它的神祕消息。

相關問題