我正在使用Linux设备驱动程序,在那里我遇到了一个令我讨厌的错误,我已经将其缩减为以下用户区代码。
目的是通过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);
}
答案 0 :(得分:0)
正如Carl Norum所说,因为你的声明并没有完全描述它对机器状态的影响,可能发生的事情是你正在破坏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,而不是实际的核心数。有thread on Intel's web forum解决了这个问题。