I recently needed to call the cpuid instruction from some C++ code. This is
well documented on wikipedia and everything
went fine until I hit a snag moving the code from x86_64 to i386.
It seems that %ebx is the PIC register for i386, and so you must take care to
not clobber it when calling cpuid. This is accompolished by explictly saving
and restoring the register before and after the call to cpuid. An additional
step is required to tell gcc that %ebx will not be clobbered by the call to
cpuid. The last lines of assembly define which registers were potentially
clobbered so gcc can generate appropriate code. By manually saving and
restoring %ebx, it can be saftely omitted from that list. I did not find any
information documenting this specifically, so here it is! The following code
returns the result of cpuid and runs on both x86_64 and i386.
void
cpuid(int regs[4], int cpuid_leaf)
{
int eax, ebx, ecx, edx;
asm volatile (
#if defined(__i386__)
“pushl %%ebx;\n\t”
#endif
“movl %4, %%eax;\n\t”
“cpuid;\n\t”
“movl %%eax, %0;\n\t”
“movl %%ebx, %1;\n\t”
“movl %%ecx, %2;\n\t”
“movl %%edx, %3;\n\t”
#if defined(__i386__)
“popl %%ebx;\n\t”
#endif
:“=m” (eax), “=m” (ebx), “=m” (ecx), “=m” (edx)
:“r” (cpuid_leaf)
:“%eax”,
#if !defined(__i386__)
“%ebx”,
#endif
“%ecx”, “%edx”);
regs[0] = eax;
regs[1] = ebx;
regs[2] = ecx;
regs[3] = edx;
}
For additional information, I found Sam Hocovar’s post to be quite informative.