Если в eax
указан ноль, инструкция cpuid
возвращает две вещи:
- в
eax
1 , максимальное значение, поддерживаемое для входного операнда в eax
для cpuid
на этом процессоре и - в
ebx
, edx
и eax
, строка «GenuineIntel», распределенная по этим регистрам в указанном порядке. Байты строки просто помещаются в регистры, по четыре байта в каждом регистре.
Код сборки, который вы показали, заставляет компилятор G CC или Clang скопировать последние регистры в ваш reg
массив.
Чтобы правильно распечатать этот массив, вы можете передать printf
:
- строку формата, содержащую
%.12s
для печати не более 12 символов и - a
char *
, который указывает на первый байт reg
.
Например:
printf("%.12s\n", (char *) reg);
(Обратите внимание, что это преобразование в char *
специально разрешено правилами псевдонимов * 1057: доступ к байтам любого объекта возможен с использованием типа указателя на символ. Другие преобразования указателя или использование их результатов не всегда определяются стандартом C. Педантически, * Может потребоваться 1038 *, поскольку он предоставляет указатель на первый байт всего массива, а не указатель на первый байт reg[0]
. Строгая интерпретация стандарта C может сказать, что последний указатель не является относительным может использоваться для арифметики c за пределами reg[0]
.)
Сноска 1: Изменение операнда только для ввода является ошибкой; компилятор будет предполагать, что EAX не изменяется в операторе asm
. В этом случае это может привести к вызову printf с al != 0
, даже если в регистрах XMM нет значений с плавающей запятой. (x86-64 Соглашение о вызовах System V.) С другими вызывающими / окружающим кодом проблемы могут быть более серьезными.
Поскольку вам не важно значение index
после выражения asm, a чтение / запись "+a"
Операнд - это простой способ сообщить компилятору, что EAX также модифицирован:
int index = 0;
int reg[3];
__asm__(
"cpuid"
: "+a"(index), "=b"(reg[0]), "=c"(reg[2]), "=d"(reg[1])
);