Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/external/gpl3/gcc/dist/gcc add the spectre mitigation option...



details:   https://anonhg.NetBSD.org/src/rev/44de0bff1974
branches:  trunk
changeset: 321624:44de0bff1974
user:      mrg <mrg%NetBSD.org@localhost>
date:      Wed Mar 28 19:22:32 2018 +0000

description:
add the spectre mitigation options for x86:

  -mindirect-branch=<choice>
  -mfunction-return=<choice>
  -mindirect-branch-register

the values for 'choice' are "keep" (default, existing behaviour),
"thunk", "thunk-inline", and "thunk-extern".

as taken from the Debian port of these changes in their
debian:gcc-6_6.3.0-18+deb9u1.diff.  i've also included the doc
updates that are missing from debian from gcc itself.


i've tested both i386 and amd64 fairly heavily with these options
enabled in both kernels and userland, atf runs and hundreds of
package builds.

diffstat:

 external/gpl3/gcc/dist/gcc/config/i386/constraints.md |    6 +-
 external/gpl3/gcc/dist/gcc/config/i386/i386-opts.h    |   13 +
 external/gpl3/gcc/dist/gcc/config/i386/i386-protos.h  |    2 +
 external/gpl3/gcc/dist/gcc/config/i386/i386.c         |  912 ++++++++++++++++-
 external/gpl3/gcc/dist/gcc/config/i386/i386.h         |   63 +-
 external/gpl3/gcc/dist/gcc/config/i386/i386.md        |   69 +-
 external/gpl3/gcc/dist/gcc/config/i386/i386.opt       |   28 +
 external/gpl3/gcc/dist/gcc/config/i386/predicates.md  |   21 +-
 external/gpl3/gcc/dist/gcc/doc/extend.texi            |   19 +
 external/gpl3/gcc/dist/gcc/doc/invoke.texi            |   36 +
 10 files changed, 1050 insertions(+), 119 deletions(-)

diffs (truncated from 1681 to 300 lines):

diff -r d56e525a8fc0 -r 44de0bff1974 external/gpl3/gcc/dist/gcc/config/i386/constraints.md
--- a/external/gpl3/gcc/dist/gcc/config/i386/constraints.md     Wed Mar 28 17:56:52 2018 +0000
+++ b/external/gpl3/gcc/dist/gcc/config/i386/constraints.md     Wed Mar 28 19:22:32 2018 +0000
@@ -172,14 +172,16 @@
 
 (define_constraint "Bs"
   "@internal Sibcall memory operand."
-  (ior (and (not (match_test "TARGET_X32"))
+  (ior (and (not (match_test "ix86_indirect_branch_register"))
+           (not (match_test "TARGET_X32"))
            (match_operand 0 "sibcall_memory_operand"))
        (and (match_test "TARGET_X32 && Pmode == DImode")
            (match_operand 0 "GOT_memory_operand"))))
 
 (define_constraint "Bw"
   "@internal Call memory operand."
-  (ior (and (not (match_test "TARGET_X32"))
+  (ior (and (not (match_test "ix86_indirect_branch_register"))
+           (not (match_test "TARGET_X32"))
            (match_operand 0 "memory_operand"))
        (and (match_test "TARGET_X32 && Pmode == DImode")
            (match_operand 0 "GOT_memory_operand"))))
diff -r d56e525a8fc0 -r 44de0bff1974 external/gpl3/gcc/dist/gcc/config/i386/i386-opts.h
--- a/external/gpl3/gcc/dist/gcc/config/i386/i386-opts.h        Wed Mar 28 17:56:52 2018 +0000
+++ b/external/gpl3/gcc/dist/gcc/config/i386/i386-opts.h        Wed Mar 28 19:22:32 2018 +0000
@@ -99,4 +99,17 @@
   SSP_GLOBAL    /* global canary */
 };
 
+/* This is used to mitigate variant #2 of the speculative execution
+   vulnerabilities on x86 processors identified by CVE-2017-5715, aka
+   Spectre.  They convert indirect branches and function returns to
+   call and return thunks to avoid speculative execution via indirect
+   call, jmp and ret.  */
+enum indirect_branch {
+  indirect_branch_unset = 0,
+  indirect_branch_keep,
+  indirect_branch_thunk,
+  indirect_branch_thunk_inline,
+  indirect_branch_thunk_extern
+};
+
 #endif
diff -r d56e525a8fc0 -r 44de0bff1974 external/gpl3/gcc/dist/gcc/config/i386/i386-protos.h
--- a/external/gpl3/gcc/dist/gcc/config/i386/i386-protos.h      Wed Mar 28 17:56:52 2018 +0000
+++ b/external/gpl3/gcc/dist/gcc/config/i386/i386-protos.h      Wed Mar 28 19:22:32 2018 +0000
@@ -311,6 +311,8 @@
 #endif
 
 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
+extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
+extern const char * ix86_output_function_return (bool long_p);
 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
                                                enum machine_mode mode);
 
diff -r d56e525a8fc0 -r 44de0bff1974 external/gpl3/gcc/dist/gcc/config/i386/i386.c
--- a/external/gpl3/gcc/dist/gcc/config/i386/i386.c     Wed Mar 28 17:56:52 2018 +0000
+++ b/external/gpl3/gcc/dist/gcc/config/i386/i386.c     Wed Mar 28 19:22:32 2018 +0000
@@ -2434,53 +2434,6 @@
   struct stack_local_entry *next;
 };
 
-/* Structure describing stack frame layout.
-   Stack grows downward:
-
-   [arguments]
-                                       <- ARG_POINTER
-   saved pc
-
-   saved static chain                  if ix86_static_chain_on_stack
-
-   saved frame pointer                 if frame_pointer_needed
-                                       <- HARD_FRAME_POINTER
-   [saved regs]
-                                       <- regs_save_offset
-   [padding0]
-
-   [saved SSE regs]
-                                       <- sse_regs_save_offset
-   [padding1]          |
-                      |                <- FRAME_POINTER
-   [va_arg registers]  |
-                      |
-   [frame]            |
-                      |
-   [padding2]         | = to_allocate
-                                       <- STACK_POINTER
-  */
-struct ix86_frame
-{
-  int nsseregs;
-  int nregs;
-  int va_arg_size;
-  int red_zone_size;
-  int outgoing_arguments_size;
-
-  /* The offsets relative to ARG_POINTER.  */
-  HOST_WIDE_INT frame_pointer_offset;
-  HOST_WIDE_INT hard_frame_pointer_offset;
-  HOST_WIDE_INT stack_pointer_offset;
-  HOST_WIDE_INT hfp_save_offset;
-  HOST_WIDE_INT reg_save_offset;
-  HOST_WIDE_INT sse_reg_save_offset;
-
-  /* When save_regs_using_mov is set, emit prologue using
-     move instead of push instructions.  */
-  bool save_regs_using_mov;
-};
-
 /* Which cpu are we scheduling for.  */
 enum attr_cpu ix86_schedule;
 
@@ -2572,7 +2525,7 @@
                                                const_tree);
 static rtx ix86_static_chain (const_tree, bool);
 static int ix86_function_regparm (const_tree, const_tree);
-static void ix86_compute_frame_layout (struct ix86_frame *);
+static void ix86_compute_frame_layout (void);
 static bool ix86_expand_vector_init_one_nonzero (bool, machine_mode,
                                                 rtx, rtx, int);
 static void ix86_add_new_builtins (HOST_WIDE_INT);
@@ -3709,12 +3662,23 @@
   return new pass_stv (ctxt);
 }
 
-/* Return true if a red-zone is in use.  */
+/* Return true if a red-zone is in use.  We can't use red-zone when
+   there are local indirect jumps, like "indirect_jump" or "tablejump",
+   which jumps to another place in the function, since "call" in the
+   indirect thunk pushes the return address onto stack, destroying
+   red-zone.
+
+   TODO: If we can reserve the first 2 WORDs, for PUSH and, another
+   for CALL, in red-zone, we can allow local indirect jumps with
+   indirect thunk.  */
 
 bool
 ix86_using_red_zone (void)
 {
-  return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI;
+  return (TARGET_RED_ZONE
+         && !TARGET_64BIT_MS_ABI
+         && (!cfun->machine->has_local_indirect_jump
+             || cfun->machine->indirect_branch_type == indirect_branch_keep));
 }
 
 /* Return a string that documents the current -m options.  The caller is
@@ -6390,6 +6354,88 @@
   ix86_previous_fndecl = NULL_TREE;
 }
 
+/* Set the indirect_branch_type field from the function FNDECL.  */
+
+static void
+ix86_set_indirect_branch_type (tree fndecl)
+{
+  if (cfun->machine->indirect_branch_type == indirect_branch_unset)
+    {
+      tree attr = lookup_attribute ("indirect_branch",
+                                   DECL_ATTRIBUTES (fndecl));
+      if (attr != NULL)
+       {
+         tree args = TREE_VALUE (attr);
+         if (args == NULL)
+           gcc_unreachable ();
+         tree cst = TREE_VALUE (args);
+         if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
+           cfun->machine->indirect_branch_type = indirect_branch_keep;
+         else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
+           cfun->machine->indirect_branch_type = indirect_branch_thunk;
+         else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
+           cfun->machine->indirect_branch_type = indirect_branch_thunk_inline;
+         else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
+           cfun->machine->indirect_branch_type = indirect_branch_thunk_extern;
+         else
+           gcc_unreachable ();
+       }
+      else
+       cfun->machine->indirect_branch_type = ix86_indirect_branch;
+
+      /* -mcmodel=large is not compatible with -mindirect-branch=thunk
+        nor -mindirect-branch=thunk-extern.  */
+      if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+         && ((cfun->machine->indirect_branch_type
+              == indirect_branch_thunk_extern)
+             || (cfun->machine->indirect_branch_type
+                 == indirect_branch_thunk)))
+       error ("%<-mindirect-branch=%s%> and %<-mcmodel=large%> are not "
+              "compatible",
+              ((cfun->machine->indirect_branch_type
+                == indirect_branch_thunk_extern)
+               ? "thunk-extern" : "thunk"));
+    }
+
+  if (cfun->machine->function_return_type == indirect_branch_unset)
+    {
+      tree attr = lookup_attribute ("function_return",
+                                   DECL_ATTRIBUTES (fndecl));
+      if (attr != NULL)
+       {
+         tree args = TREE_VALUE (attr);
+         if (args == NULL)
+           gcc_unreachable ();
+         tree cst = TREE_VALUE (args);
+         if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
+           cfun->machine->function_return_type = indirect_branch_keep;
+         else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
+           cfun->machine->function_return_type = indirect_branch_thunk;
+         else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
+           cfun->machine->function_return_type = indirect_branch_thunk_inline;
+         else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
+           cfun->machine->function_return_type = indirect_branch_thunk_extern;
+         else
+           gcc_unreachable ();
+       }
+      else
+       cfun->machine->function_return_type = ix86_function_return;
+
+      /* -mcmodel=large is not compatible with -mfunction-return=thunk
+        nor -mfunction-return=thunk-extern.  */
+      if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+         && ((cfun->machine->function_return_type
+              == indirect_branch_thunk_extern)
+             || (cfun->machine->function_return_type
+                 == indirect_branch_thunk)))
+       error ("%<-mfunction-return=%s%> and %<-mcmodel=large%> are not "
+              "compatible",
+              ((cfun->machine->function_return_type
+                == indirect_branch_thunk_extern)
+               ? "thunk-extern" : "thunk"));
+    }
+}
+
 /* Establish appropriate back-end context for processing the function
    FNDECL.  The argument might be NULL to indicate processing at top
    level, outside of any function scope.  */
@@ -6400,7 +6446,13 @@
      several times in the course of compiling a function, and we don't want to
      slow things down too much or call target_reinit when it isn't safe.  */
   if (fndecl == ix86_previous_fndecl)
-    return;
+    {
+      /* There may be 2 function bodies for the same function FNDECL,
+        one is extern inline and one isn't.  */
+      if (fndecl != NULL_TREE)
+       ix86_set_indirect_branch_type (fndecl);
+      return;
+    }
 
   tree old_tree;
   if (ix86_previous_fndecl == NULL_TREE)
@@ -6417,6 +6469,8 @@
       return;
     }
 
+  ix86_set_indirect_branch_type (fndecl);
+
   tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
   if (new_tree == NULL_TREE)
     new_tree = target_option_default_node;
@@ -10927,7 +10981,6 @@
 bool
 ix86_can_use_return_insn_p (void)
 {
-  struct ix86_frame frame;
 
   if (! reload_completed || frame_pointer_needed)
     return 0;
@@ -10937,7 +10990,8 @@
   if (crtl->args.pops_args && crtl->args.size >= 32768)
     return 0;
 
-  ix86_compute_frame_layout (&frame);
+  ix86_compute_frame_layout ();
+  struct ix86_frame &frame = cfun->machine->frame;
   return (frame.stack_pointer_offset == UNITS_PER_WORD
          && (frame.nregs + frame.nsseregs) == 0);
 }
@@ -11002,6 +11056,267 @@
 # endif
 #endif
 
+/* Label count for call and return thunks.  It is used to make unique
+   labels in call and return thunks.  */
+static int indirectlabelno;
+
+/* True if call and return thunk functions are needed.  */
+static bool indirect_thunk_needed = false;
+/* True if call and return thunk functions with the BND prefix are
+   needed.  */
+static bool indirect_thunk_bnd_needed = false;
+
+/* Bit masks of integer registers, which contain branch target, used
+   by call and return thunks functions.  */
+static int indirect_thunks_used;
+/* Bit masks of integer registers, which contain branch target, used
+   by call and return thunks functions with the BND prefix.  */
+static int indirect_thunks_bnd_used;
+
+#ifndef INDIRECT_LABEL



Home | Main Index | Thread Index | Old Index