Re: [RFC, PATCHv1 15/28] x86: detect 5-level paging support
From: hpa
Date: Thu Dec 15 2016 - 12:53:27 EST
On December 15, 2016 6:39:44 AM PST, Borislav Petkov <bp@xxxxxxxxx> wrote:
>On Wed, Dec 14, 2016 at 12:07:54AM +0100, Boris Petkov wrote:
>> Thus I was thinking of adding a build-time check for the gcc version
>> but that might turn out to be more code in the end than those ugly
>> ifnc clauses.
>
>IOW, something like this. I did this just to try to see whether it is
>doable. And it does work - gcc 4.8 and 4.9 -m32 cannot preserve the PIC
>register - actually the inline asm fails building due to impossible
>constraints.
>
>However, so many lines changed just to save the ifnc, meh, I dunno...
>
>---
> arch/x86/boot/compressed/Makefile | 8 ++++++
> arch/x86/boot/cpuflags.c | 14 ++++++++--
>scripts/gcc-clobber-pic.sh | 58
>+++++++++++++++++++++++++++++++++++++++
> 3 files changed, 77 insertions(+), 3 deletions(-)
> create mode 100755 scripts/gcc-clobber-pic.sh
>
>diff --git a/arch/x86/boot/compressed/Makefile
>b/arch/x86/boot/compressed/Makefile
>index 34d9e15857c3..705fc2ab3fd6 100644
>--- a/arch/x86/boot/compressed/Makefile
>+++ b/arch/x86/boot/compressed/Makefile
>@@ -35,6 +35,14 @@ KBUILD_CFLAGS += -mno-mmx -mno-sse
> KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
> KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
>
>+# check whether inline asm clobbers the PIC register
>+ifeq ($(CONFIG_X86_32),y)
>+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-clobber-pic.sh
>$(CC) -m32),n)
>+ KBUILD_CFLAGS += -DCC_PRESERVES_PIC
>+ KBUILD_AFLAGS += -DCC_PRESERVES_PIC
>+endif
>+endif
>+
> KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
> GCOV_PROFILE := n
> UBSAN_SANITIZE :=n
>diff --git a/arch/x86/boot/cpuflags.c b/arch/x86/boot/cpuflags.c
>index 6687ab953257..913c3f5ab3a0 100644
>--- a/arch/x86/boot/cpuflags.c
>+++ b/arch/x86/boot/cpuflags.c
>@@ -70,11 +70,19 @@ int has_eflag(unsigned long mask)
> # define EBX_REG "=b"
> #endif
>
>+#if defined(__i386__) && defined(__PIC__) &&
>!defined(CC_PRESERVES_PIC)
>+# define SAVE_PIC ".ifnc %%ebx, %3; movl %%ebx, %3; .endif\n\t"
>+# define SWAP_PIC ".ifnc %%ebx, %3; xchgl %%ebx, %3; .endif\n\t"
>+#else
>+# define SAVE_PIC
>+# define SWAP_PIC
>+#endif
>+
> static inline void cpuid(u32 id, u32 *a, u32 *b, u32 *c, u32 *d)
> {
>- asm volatile(".ifnc %%ebx,%3 ; movl %%ebx,%3 ; .endif \n\t"
>- "cpuid \n\t"
>- ".ifnc %%ebx,%3 ; xchgl %%ebx,%3 ; .endif \n\t"
>+ asm volatile(SAVE_PIC
>+ "cpuid\n\t"
>+ SWAP_PIC
> : "=a" (*a), "=c" (*c), "=d" (*d), EBX_REG (*b)
> : "a" (id)
> );
>diff --git a/scripts/gcc-clobber-pic.sh b/scripts/gcc-clobber-pic.sh
>new file mode 100755
>index 000000000000..7ff10edf9b08
>--- /dev/null
>+++ b/scripts/gcc-clobber-pic.sh
>@@ -0,0 +1,58 @@
>+#!/bin/bash -x
>+err=0
>+O=$(mktemp)
>+cat << "END" | $@ -fPIC -x c - -o $O >/dev/null 2>&1 || err=1
>+int some_global_var, some_other_global_var;
>+
>+typedef unsigned int u32;
>+
>+void __attribute__((noinline)) foo(void)
>+{
>+ asm volatile("# some crap just so that we don't get optimized away");
>+
>+ some_other_global_var = 43;
>+}
>+
>+static inline void cpuid(u32 id, u32 *a, u32 *b, u32 *c, u32 *d)
>+{
>+ asm volatile("cpuid"
>+ : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
>+ : "a" (id), "2" (*c)
>+ : "si", "di"
>+ );
>+
>+ some_global_var = 42;
>+ foo();
>+}
>+
>+int main(void)
>+{
>+ u32 a, b, c = 0, d;
>+
>+ cpuid(0x1, &a, &b, &c, &d);
>+
>+ /*
>+ * Make sure foo() gets actually called and not optimized away due to
>+ * miscompilation.
>+ */
>+ if (some_global_var == 42 && some_other_global_var == 43)
>+ return 0;
>+ else
>+ return 1;
>+}
>+END
>+
>+if (( $err ));
>+then
>+ exit 1
>+fi
>+
>+chmod u+x $O
>+$O
>+
>+if ! (( $? ));
>+then
>+ echo "n"
>+fi
>+
>+rm -f $O
This really is only worthwhile if it ends up producing better code, but I doubt it.
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.