c语言 - 为什么将 CPUID 结果存储在 int 数组中并传递给 printf "%s" ?


#include <stdio.h>
int main() {
int index = 0;
int reg[3];
__asm__(
"cpuid nt"
: "=b"(reg[0]), "=c"(reg[2]), "=d"(reg[1])
// editor's note: CPUID also modifies EAX; this buggy code doesn't tell the compiler about it
: "a"(index)); 
printf("%sn",&reg);
}

为什么int被视为字符串。我需要一些帮助来解释为什么会这样。

eax中给定零时,cpuid指令返回两件事:

  • eax1中,此处理器上cpuideax中输入操作数支持的最大值,以及
  • ebxedxeax中,字符串"GenuineIntel"按顺序分布在这些寄存器中。字符串的字节被简单地放入寄存器中,每个寄存器中有四个字节

显示的汇编代码会导致GCC或Clang编译器将后一个寄存器复制到reg数组中。

要正确打印此数组,可以传递到printf:

  • 包含%.12s的格式字符串,最多可打印12个字符,以及
  • 指向CCD_ 13的第一字节的CCD_

例如:

printf("%.12sn", (char *) reg);

(请注意,这种到char *的转换是C别名规则特别允许的:任何对象的字节都可以使用指向字符类型的指针来访问。其他指针转换或其结果的使用并不总是由C标准定义的。从教学角度来看,可能需要(char *) &reg,因为它提供了指向整个数组第一个字节的指针,而不是指向CCD_ 16。对C标准的严格解释可以说,后一个指针对于reg[0]以外的算术来说是不可靠的。(


脚注1:修改仅输入操作数是一个错误;编译器将假定EAX在CCD_ 18语句中是未修改的。在这种情况下,这可能导致使用al != 0调用printf,即使XMM寄存器中没有浮点值。(x86-64 System V调用约定。(对于其他调用方/周围代码,问题可能会更严重。

由于您不关心asm语句后index的值,因此在这种情况下,读/写"+a"操作数是告诉编译器EAX也被修改的一种简单方法:

int index = 0;
int reg[3];
__asm__(
"cpuid"
: "+a"(index), "=b"(reg[0]), "=c"(reg[2]), "=d"(reg[1])
);

最新更新