]> wimlib.net Git - wimlib/blobdiff - src/x86_cpu_features.c
decompress_common: move temp space for building decode table to heap
[wimlib] / src / x86_cpu_features.c
index f83475751689258a1b0d5a42f1d5ca49434f4a7a..3995413d6495b518181fcc2a843211f9a90b3fc7 100644 (file)
@@ -1,15 +1,27 @@
 /*
- * x86_cpu_features.c
+ * x86_cpu_features.c - feature detection for x86 processors
  *
- * Feature detection for x86 processors.
+ * The following copying information applies to this specific source code file:
  *
- * Author:     Eric Biggers
- * Year:       2015
+ * Written in 2015 by Eric Biggers <ebiggers3@gmail.com>
  *
- * The author dedicates this file to the public domain.
- * You can do whatever you want with this file.
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide via the Creative Commons Zero 1.0 Universal Public Domain
+ * Dedication (the "CC0").
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the CC0 for more details.
+ *
+ * You should have received a copy of the CC0 along with this software; if not
+ * see <http://creativecommons.org/publicdomain/zero/1.0/>.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
 #include "wimlib/x86_cpu_features.h"
 
 #if defined(__i386__) || defined(__x86_64__)
 
 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.  */
@@ -37,7 +59,9 @@ read_xcr(u32 index)
 {
        u32 edx, eax;
 
-       __asm__ ("xgetbv" : "=d" (edx), "=a" (eax) : "c" (index));
+       /* Execute the "xgetbv" instruction.  Old versions of binutils do not
+        * recognize this instruction, so list the raw bytes instead.  */
+       __asm__ (".byte 0x0f, 0x01, 0xd0" : "=d" (edx), "=a" (eax) : "c" (index));
 
        return ((u64)edx << 32) | eax;
 }