* You can do whatever you want with this file.
*/
+#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;
}