/*
- * 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. */
{
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;
}