繁体   English   中英

C和内联asm错误

[英]C and inline asm bug

我正在使用Linux设备驱动程序,在其中遇到了一个令人讨厌的错误,我将其简化为下面的userland代码。

目的是通过cpuid指令读取处理器中的内核数

看来,一个核心转储在第三阶段产生的,我坚持了一个解释?

输出:

Phase 1: FYI Proc=0x1ac1010
Phase 2: CPU count=8
Segmentation fault (core dumped)

此代码是针对Linux 4.0.7-2 64位编写的,使用gcc版本5.1.0进行了编译

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    unsigned long CPU_count;
} PROC;

PROC *Proc=NULL;

unsigned long CPU_count;

unsigned long CPU_Count(void)
{
    unsigned long c=0;

    __asm__ volatile
    (
        "movq   $0x4, %%rax     \n\t"
        "xorq   %%rcx, %%rcx    \n\t"
        "cpuid                  \n\t"
        "shr    $26, %%rax      \n\t"
        "and    $0x3f, %%rax    \n\t"
        "inc    %%rax           \n\t"
        "movq   %%rax, %0"
        : "=m" (c)
        :
        : "rax", "memory"
    );
    return(c);
}

int main(int argc, char *argv[])
{
    if((Proc=malloc(sizeof(PROC))) != NULL)
    {
        printf("Phase 1: FYI Proc=%p\n", Proc);

        CPU_count=CPU_Count();
        printf("Phase 2: CPU count=%lu\n", CPU_count);

        Proc->CPU_count=CPU_Count();
        printf("Phase 3: CPU count=%lu\n", Proc->CPU_count);

        free(Proc);
        return(0);
    }
    else
        return(-1);
}

正如Carl Norum所提到的那样,由于您的asm语句不能完全描述其对计算机状态的影响,可能是正在破坏GCC正在用来存储某些值的寄存器。 像说Proc指针。

解决方案是定义汇编指令的所有输入和输出,以及其他任何令人讨厌的东西。 在这种情况下,最好尽量减少内联汇编的工作,而将其他所有工作留给编译器。 在您的示例中,仅cpuid指令需要进行内联汇编。 因此,请尝试以下操作:

void
cpuid(unsigned value, unsigned leaf,
      unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) {
    asm volatile("cpuid"
             : "=a" (*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
             : "a" (value), "c" (leaf));
}

unsigned long int CPU_Count(void)
{
    unsigned eax, ebx, ecx, edx;
    cpuid(4, 0, &eax, &ebx, &ecx, &edx);
    return ((eax >> 26) & 0x3F) + 1;
}

请注意,您确定CPU内核数的方法将无法可靠地工作。 在我的4核CPU上,您的程序说我有8核。 这是因为您要提取的字段会提供最大的APIC ID,而不是实际的内核数。 英特尔的网络论坛上有一个主题可以解决这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM