用gcc -m32 -march=i686 -Os编译之后,mpicalc --print-config报告的CPU特性不对,经过调试,最后发现是get_cpuid()出了问题,在这里记录一下。
以上get_cpuid()来自libgcrypt 1.9.2. 在特定的编译参数下,会生成下面的代码:
结果就是执行了cpuid之后,本来代码是想把ebx的值存到另一个地方的,但是mov %ebx,%ebx使得ebx的值没被保存下来,于是后续代码想用ebx的值的时候就错了。产生这样的代码应该和寄存器分配有关。
由于libgcrypt的get_cpuid()在32位和64位的x86体系结构的实现代码不同,所以x86_64的系统中没发现有这样的问题。
compiler explorer 输出 https://gcc.godbolt.org/z/7e3scE5a7
代码:
#define NULL ((void*)0)
static void
get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
unsigned int regs[4];
asm volatile
("movl %%ebx, %%edi\n\t" /* Save GOT register. */
"xorl %%ebx, %%ebx\n\t"
"cpuid\n\t"
"movl %%ebx, %1\n\t"
"movl %%edi, %%ebx\n\t" /* Restore GOT register. */
: "=a" (regs[0]), "=g" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "0" (in), "2" (0), "3" (0)
: "cc", "edi"
);
if (eax)
*eax = regs[0];
if (ebx)
*ebx = regs[1];
if (ecx)
*ecx = regs[2];
if (edx)
*edx = regs[3];
}
unsigned int feature_detect()
{
unsigned int fms, family, model, features, features2;
unsigned int result = 0;
get_cpuid(1, &fms, NULL, &features, &features2);
family = ((fms & 0xf00) >> 8) + ((fms & 0xff00000) >> 20);
model = ((fms & 0xf0) >> 4) + ((fms & 0xf0000) >> 12);
if (family == 6) {
if (model == 0x3a) {
result |= 1;
}
get_cpuid(7, NULL, &features, NULL, NULL);
// in my machine features=0x281
if (features & 0x00000001) {
result |= 2;
}
}
return result;
}
int main()
{
return feature_detect();
}
以上get_cpuid()来自libgcrypt 1.9.2. 在特定的编译参数下,会生成下面的代码:
代码:
mov $0x7,%eax
mov %ecx,%edx
mov %ebx,%edi
xor %ebx,%ebx
cpuid
mov %ebx,%ebx
mov %edi,%ebx
结果就是执行了cpuid之后,本来代码是想把ebx的值存到另一个地方的,但是mov %ebx,%ebx使得ebx的值没被保存下来,于是后续代码想用ebx的值的时候就错了。产生这样的代码应该和寄存器分配有关。
由于libgcrypt的get_cpuid()在32位和64位的x86体系结构的实现代码不同,所以x86_64的系统中没发现有这样的问题。
compiler explorer 输出 https://gcc.godbolt.org/z/7e3scE5a7