x86_cpu_features.c: cpuid fix for x86_32 PIC with old GCC versions
authorEric Biggers <ebiggers3@gmail.com>
Sat, 22 Aug 2015 16:27:12 +0000 (11:27 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 22 Aug 2015 16:32:56 +0000 (11:32 -0500)
src/x86_cpu_features.c

index f83475751689258a1b0d5a42f1d5ca49434f4a7a..aab200ffe5f2bb9b682592f8c4dee461234c2dbd 100644 (file)
 
 u32 _x86_cpu_features = 0;
 
+/* With old GCC versions we have to manually save and restore the x86_32 PIC
+ * register (ebx).  See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602  */
+#if defined(__i386__) && defined(__PIC__)
+#  define EBX_CONSTRAINT "=r"
+#else
+#  define EBX_CONSTRAINT "=b"
+#endif
+
 /* Execute the CPUID instruction.  */
 static inline void
-cpuid(u32 leaf, u32 subleaf, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+cpuid(u32 leaf, u32 subleaf, u32 *a, u32 *b, u32 *c, u32 *d)
 {
-       __asm__ ("cpuid"
-                : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
-                : "a" (leaf), "c" (subleaf));
+       __asm__(".ifnc %%ebx, %1; mov  %%ebx, %1; .endif\n"
+               "cpuid                                  \n"
+               ".ifnc %%ebx, %1; xchg %%ebx, %1; .endif\n"
+               : "=a" (*a), EBX_CONSTRAINT (*b), "=c" (*c), "=d" (*d)
+               : "a" (leaf), "c" (subleaf));
 }
 
 /* Read an extended control register.  */