我想使用cpuid指令来识别Intel CPU的特性。我在Kernel.framework中找到了cpuid.h头文件,所以我将Kernel.framework添加到我的项目中,并在源文件中包含了<Kernel/i386/cpuid.h>。产生的
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"
但是解决这个问题的方法是使用动态-无选择选项(GCC_DYNAMIC_NO_PIC构建设置),Xcode对构建设置的帮助说“不适合共享库(需要位置无关)”。我正在构建一个框架,我认为它是一个共享库。那我该怎么做呢?
发布于 2015-09-13 03:18:11
这条相当神秘的错误消息:
error: can't find a register in class 'BREG' while reloading 'asm'
error: 'asm' operand has impossible constraints是因为其中一个约束是不允许的。在这种情况下,它是EBX。当使用-fPIC选项(位置无关代码)编译32位代码时,使用EBX寄存器进行重新定位。它不能用作输出,也不能显示为失败的寄存器。
尽管大多数人建议使用特殊的编译器标志进行编译,但是可以通过修改汇编程序代码来保存EBX寄存器本身并在此之后恢复它,从而重新编写函数以支持x86-64/ it 32和PIC/non。这可以通过如下代码来完成:
#include <inttypes.h>
static inline void
do_cpuid(uint32_t selector, uint32_t *data)
{
__asm__ __volatile__ (
"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),
"c"(0));
}重要的更改是,data[1]值将在编译器选择的可用寄存器中返回。=&r约束告诉编译器,它选择的任何寄存器都不能是任何其他输入寄存器(我们早期用xchg代码关闭寄存器)。在代码中,我们使用编译器选择的可用寄存器交换EBX。然后我们再把它换回来。完成后,EBX将包含其原始值,所选择的空闲寄存器将包含CPUID返回的内容。然后汇编程序模板将该空闲寄存器的内容移动到data[1]。
实际上,我们通过允许编译器选择一个免费寄存器来规避这个问题。编译器很聪明,如果它被绑定,就不会使用EBX,因为它可能用于可重定位的代码。在64位代码中,EBX不像32位代码那样用于重定位,因此可以使用它。
精明的观察者可能已经注意到了xor %%ecx,%%ecx。这是一个独立于EBX问题的改变。现在人们认为清除ECX是一种很好的做法,因为如果ECX不是零,一些由ECX制造的处理器可能会返回陈旧的值。如果您只为非PPC Mac平台开发,这种更改是不必要的,因为苹果公司使用的英特尔处理器没有这种行为。
通常,EBX在32位可重定位/PIC代码中是特殊的,这就是编译器最初抱怨其神秘消息的原因。
发布于 2019-10-15 16:47:34
因此,这可能不会回答这个问题,但至少应该为一些人找到自己的解决办法提供一个足够有趣的解决办法。
sysctl在macOS上提供了大量关于机器CPU的信息。对于初学者,在终端中键入man sysctl,并查看以machdep.cpu为前缀的所有内容。例如,以feature_bits代替cpuid.h中的uint64_t cpuid_features(void);
sysctl machdep.cpu.feature_bits为您提供了实际的功能位掩码,尽管不是很容易读。sysctl machdep.cpu.features的工作做得更好,并为您提供了基本可理解的缩略语。
现在,以编程的方式这样做更有趣,而且实际上是相当可行的:
#include <sys/sysctl.h>
// ...
int64_t value = 0;
size_t valueByteSize = sizeof(value);
int error = sysctlbyname("machdep.cpu.feature_bits", &value, &valueByteSize, NULL, 0);
if (!error)
{
// Check for the next best bit defined in cpuid.h
// Since you can't build with cpuid.h directly, just copy over the definitions you actually need
bool hasFPU = value & CPUID_FEATURE_FPU;
}https://stackoverflow.com/questions/12221646
复制相似问题