首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与高级语言使用CPUID的不同

与高级语言使用CPUID的不同
EN

Stack Overflow用户
提问于 2016-07-20 15:24:31
回答 1查看 629关注 0票数 0

我试图利用需要特定处理器体系结构的x86 ASM函数。我知道在调用"CPUID标准函数01H“之后,需要检查一个特定的位。下面是调用CPUID的C实现,它来自CPUID维基百科页面:

代码语言:javascript
复制
#include <stdio.h>

int main() {
    int i;
    unsigned int index = 0;
    unsigned int regs[4];
    int sum;
    __asm__ __volatile__(
#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64)
        "pushq %%rbx     \n\t" /* save %rbx */
#else
        "pushl %%ebx     \n\t" /* save %ebx */
#endif
        "cpuid            \n\t"
        "movl %%ebx ,%[ebx]  \n\t" /* write the result into output var */
#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64)
        "popq %%rbx \n\t"
#else
        "popl %%ebx \n\t"
#endif
        : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
        : "a"(index));
    for (i=4; i<8; i++) {
        printf("%c" ,((char *)regs)[i]);
    }
    for (i=12; i<16; i++) {
        printf("%c" ,((char *)regs)[i]);
    }
    for (i=8; i<12; i++) {
        printf("%c" ,((char *)regs)[i]);
    }
    printf("\n");
}

尽管Linux内核使用以下函数:

代码语言:javascript
复制
static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
                                unsigned int *ecx, unsigned int *edx)
{
        /* ecx is often an input as well as an output. */
        asm volatile("cpuid"
            : "=a" (*eax),
              "=b" (*ebx),
              "=c" (*ecx),
              "=d" (*edx)
            : "0" (*eax), "2" (*ecx));
}

哪一个更好?其他本质上等同的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-21 09:38:46

正如Jester所说,GNU中的-- cpuid.h 包装器的内在特性--可能是最好的选择。

还有__builtin_cpu_supports("popcnt")"avx"之类的,在您调用__builtin_cpu_init()之后就可以工作了。不过,只有真正重要的特征位才能得到支持。例如,文档没有提到rdrand的特性位,因此__builtin_cpu_supports("rdrand")可能无法工作。

自定义内联装配版本:

Linux的实现可以在没有浪费指令的情况下内联,而且它看起来写得很好,所以没有理由使用其他任何东西。您可能会收到关于不能满足"=b"约束的抱怨;如果是这样,请参见下面clang的cpuid.h所做的工作。(但我认为这是不必要的,也是文档错误的结果)。

但是,如果您将它用于生成的值,而不是管道上的序列化效果,那么它实际上并不需要volatile:使用相同输入的CPUID将产生相同的结果,因此我们可以让优化器将其移动或将其吊出循环。(因此运行次数较少)。这可能没有什么帮助,因为普通代码一开始就不会在循环中使用它。

cpuid.h做了一些奇怪的事情,比如保存%rbx,因为很明显,一些x86-64环境可能无法满足使用%rbx作为输出操作数的约束?评论是/* x86-64 uses %rbx as the base register, so preserve it. */,但我不知道他们在说什么。如果有任何x86-32PIC代码在SysV ABI中使用%ebx作为一个固定用途(作为指向GOT的指针),但是我不知道x86-64中有什么类似的东西。也许这段代码是由ABI文档中的错误驱动的?见陆志强的邮寄名单上有关此事的帖子

最重要的是,--问题 (inside main()) 中的第一个版本--是坏的,因为它是push

要修复它,只需告诉编译器结果将在ebx中(使用"=b"),并让它担心在函数开始/结束时保存/恢复ebx/rbx。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38484616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档