#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",®);
}
为什么int被视为字符串。我需要一些帮助来解释为什么会这样。
当eax
中给定零时,cpuid
指令返回两件事:
- 在
eax
1中,此处理器上cpuid
的eax
中输入操作数支持的最大值,以及 - 在
ebx
、edx
和eax
中,字符串"GenuineIntel"按顺序分布在这些寄存器中。字符串的字节被简单地放入寄存器中,每个寄存器中有四个字节
显示的汇编代码会导致GCC或Clang编译器将后一个寄存器复制到reg
数组中。
要正确打印此数组,可以传递到printf
:
- 包含
%.12s
的格式字符串,最多可打印12个字符,以及 - 指向CCD_ 13的第一字节的CCD_
例如:
printf("%.12sn", (char *) reg);
(请注意,这种到char *
的转换是C别名规则特别允许的:任何对象的字节都可以使用指向字符类型的指针来访问。其他指针转换或其结果的使用并不总是由C标准定义的。从教学角度来看,可能需要(char *) ®
,因为它提供了指向整个数组第一个字节的指针,而不是指向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])
);