如何在Mac框架中调用cpuid指令? [英] How to call cpuid instruction in a Mac framework?

查看:161
本文介绍了如何在Mac框架中调用cpuid指令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用cpuid指令来识别Intel CPU的功能.我在Kernel.framework中找到了cpuid.h标头,因此我将Kernel.framework添加到了项目中,并在源文件中包含了<Kernel/i386/cpuid.h>.产生了

I want to use the cpuid instruction to identify features of an Intel CPU. I found the cpuid.h header in Kernel.framework, so I added Kernel.framework to my project and included <Kernel/i386/cpuid.h> in my source file. That produced

kern/kern_types.h: No such file or directory

我不明白.但是我想使用的函数do_cpuid是内联定义的,因此我尝试将其复制到源代码中.

which I don't understand. But the function do_cpuid, which is what I think I want to use, is defined inline, so I tried just copying that into my source.

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

搜索该错误导致我遇到以下问题:

Googling that error led me to this question: Problem on Mac : "Can't find a register in class BREG while reloading asm"

但是该问题的解决方案是使用dynamic-no-pic选项(GCC_DYNAMIC_NO_PIC构建设置),Xcode的构建设置帮助显示不适用于共享库(需要与位置无关). "我正在建立一个框架,我认为这是一个共享库.那我该如何做呢?

But the solution to that question was to use the dynamic-no-pic option (GCC_DYNAMIC_NO_PIC build setting), and Xcode's help on build settings says "Not appropriate for shared libraries (which need to be position-independent)." I'm building a framework, which I think counts as a shared library. So how can I make this work?

推荐答案

这条颇为隐秘的错误消息:

This rather cryptic error message:

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

发生

是因为不允许其中一个约束.在这种情况下,它是EBX.当使用-fPIC选项编译32位代码(与位置无关的代码)时,EBX寄存器用于重定位.它不能用作输出或显示为破坏寄存器.

is occurring because one of the constraints isn't allowed. In this case it is EBX. When compiling 32 bit code with the -fPIC option (position independent code) the EBX register is used for relocation. It can't be used as an output or appear as a clobbered register.

尽管大多数人建议使用特殊的编译器标志进行编译,但是可以重写该函数以支持 x86-64 / IA32 PIC / non-PIC ,方法是修改汇编代码以保存EBX寄存器本身,然后再将其还原.可以使用以下代码完成此操作:

Although most people suggest compiling with special compiler flags, the function can be rewritten to support x86-64/IA32 and PIC/non-PIC by modifying the assembler code to save the EBX register itself and restore it after. This can be done with code like:

#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].

The significant change is that the data[1] value will be returned in an available register the compiler chooses. The =&r constraint tells the compiler that whatever register it chooses can't be any of the other input registers (we early clobber the register with the xchg code). In the code we exchange EBX with available register the compiler chose. We then exchange it back afterward. When finished EBX will contain its original value and the free register that was chosen will contain what was returned by CPUID. The assembler template will then move the contents of that free register to data[1].

实际上,我们通过允许编译器选择一个自由寄存器来解决了这个问题.如果编译器被捆绑在一起,那么它足够聪明,不会使用EBX,因为它可能用于可重定位的代码.在64位代码中,EBX不能像32位代码那样用于重新定位,因此可以使用.

Effectively we have circumvented the problem by allowing the compiler to choose a free register. The compiler is smart enough not to use EBX if it is tied up because it might be used for relocatable code. In 64 bit code EBX isn't used for relocation like it is with 32 bit code so it may be available for usage.

一个敏锐的观察者可能已经注意到了xor %%ecx,%%ecx.这是我独立于EBX问题所做的更改.现在,清除ECX被认为是一种好习惯,因为如果ECX不为零,则AMD制造的某些处理器可能会返回陈旧的值.如果您仅针对非PPC Mac平台进行开发,则无需进行此更改,因为Apple使用的英特尔处理器不会表现出这种行为.

An astute observer might have noticed the xor %%ecx,%%ecx. This is a change I made independent of the EBX issue. It is now considered good practice to clear ECX because some processors made by AMD may return stale values if ECX is not zero. If you are developing for a non-PPC Mac platform only, this change isn't necessary since Apple uses Intel processors that don't exhibit such behavior.

通常EBX在32位可重定位/PIC代码中是特殊的,这就是为什么编译器最初抱怨其隐秘消息的原因.

Generally EBX is special in 32 bit relocatable/PIC code which is why the compiler originally complained with its cryptic message.

这篇关于如何在Mac框架中调用cpuid指令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆