X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fx86_cpu_features.c;h=5e434f9f0b18cfcb36ca9559baed4d671d0ec1c7;hp=f83475751689258a1b0d5a42f1d5ca49434f4a7a;hb=56c8b5eaacef8a5563261b9034a8a011480bba6e;hpb=b72a7e56778f04f4e38e093906c4e4846e165ff3 diff --git a/src/x86_cpu_features.c b/src/x86_cpu_features.c index f8347575..5e434f9f 100644 --- a/src/x86_cpu_features.c +++ b/src/x86_cpu_features.c @@ -22,13 +22,23 @@ 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 +47,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; }