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 Ubuntu port of these changes in their
ubuntu:gcc-5_5.5.0-8ubuntu1.diff.  i've also included the doc
updates that are missing from ubuntu 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.

XXX: pullup-8 to gcc/ not gcc.old/
This commit is contained in:
mrg 2018-03-28 19:24:52 +00:00
parent 67e62e9db5
commit 7032fd789a
10 changed files with 1019 additions and 98 deletions

View File

@ -157,12 +157,14 @@
(define_constraint "Bs"
"@internal Sibcall memory operand."
(and (not (match_test "TARGET_X32"))
(and (not (match_test "ix86_indirect_branch_register"))
(not (match_test "TARGET_X32"))
(match_operand 0 "sibcall_memory_operand")))
(define_constraint "Bw"
"@internal Call memory operand."
(and (not (match_test "TARGET_X32"))
(and (not (match_test "ix86_indirect_branch_register"))
(not (match_test "TARGET_X32"))
(match_operand 0 "memory_operand")))
(define_constraint "Bz"

View File

@ -99,4 +99,17 @@ enum stack_protector_guard {
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

View File

@ -306,6 +306,8 @@ extern enum attr_cpu ix86_schedule;
#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);
#ifdef RTX_CODE
/* Target data for multipass lookahead scheduling.

File diff suppressed because it is too large Load Diff

View File

@ -1210,6 +1210,9 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
/* Base register for access to local variables of the function. */
#define FRAME_POINTER_REGNUM 20
#define FIRST_INT_REG AX_REG
#define LAST_INT_REG SP_REG
/* First floating point reg */
#define FIRST_FLOAT_REG 8
@ -1446,6 +1449,8 @@ enum reg_class
registers. */
#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
#define LEGACY_INT_REGNO_P(N) (IN_RANGE ((N), FIRST_INT_REG, LAST_INT_REG))
#define QI_REG_P(X) (REG_P (X) && QI_REGNO_P (REGNO (X)))
#define QI_REGNO_P(N) IN_RANGE ((N), AX_REG, BX_REG)
@ -2390,9 +2395,56 @@ enum avx_u128_state
#define FASTCALL_PREFIX '@'
#ifndef USED_FOR_TARGET
/* 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 GTY(()) 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;
};
/* Machine specific frame tracking during prologue/epilogue generation. */
#ifndef USED_FOR_TARGET
struct GTY(()) machine_frame_state
{
/* This pair tracks the currently active CFA as reg+offset. When reg
@ -2438,6 +2490,9 @@ struct GTY(()) machine_function {
int varargs_fpr_size;
int optimize_mode_switching[MAX_386_ENTITIES];
/* Cached initial frame layout for the current function. */
struct ix86_frame frame;
/* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE
has been computed for. */
int use_fast_prologue_epilogue_nregs;
@ -2481,6 +2536,16 @@ struct GTY(()) machine_function {
/* If true, it is safe to not save/restore DRAP register. */
BOOL_BITFIELD no_drap_save_restore : 1;
/* How to generate indirec branch. */
ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3;
/* If true, the current function has local indirect jumps, like
"indirect_jump" or "tablejump". */
BOOL_BITFIELD has_local_indirect_jump : 1;
/* How to generate function return. */
ENUM_BITFIELD(indirect_branch) function_return_type : 3;
/* During prologue/epilogue generation, the current frame state.
Otherwise, the frame state at the end of the prologue. */
struct machine_frame_state fs;
@ -2505,6 +2570,7 @@ struct GTY(()) machine_function {
#define ix86_current_function_calls_tls_descriptor \
(ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
#define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
/* Control behavior of x86_file_start. */
#define X86_FILE_START_VERSION_DIRECTIVE false

View File

@ -11585,15 +11585,20 @@
[(set (pc) (match_operand 0 "indirect_branch_operand"))]
""
{
if (TARGET_X32)
if (TARGET_X32 || ix86_indirect_branch_register)
operands[0] = convert_memory_address (word_mode, operands[0]);
cfun->machine->has_local_indirect_jump = true;
})
(define_insn "*indirect_jump"
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
""
"%!jmp\t%A0"
[(set_attr "type" "ibr")
"* return ix86_output_indirect_jmp (operands[0], false);"
[(set (attr "type")
(if_then_else (match_test "(cfun->machine->indirect_branch_type
!= indirect_branch_keep)")
(const_string "multi")
(const_string "ibr")))
(set_attr "length_immediate" "0")])
(define_expand "tablejump"
@ -11633,16 +11638,21 @@
OPTAB_DIRECT);
}
if (TARGET_X32)
if (TARGET_X32 || ix86_indirect_branch_register)
operands[0] = convert_memory_address (word_mode, operands[0]);
cfun->machine->has_local_indirect_jump = true;
})
(define_insn "*tablejump_1"
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
(use (label_ref (match_operand 1)))]
""
"%!jmp\t%A0"
[(set_attr "type" "ibr")
"* return ix86_output_indirect_jmp (operands[0], false);"
[(set (attr "type")
(if_then_else (match_test "(cfun->machine->indirect_branch_type
!= indirect_branch_keep)")
(const_string "multi")
(const_string "ibr")))
(set_attr "length_immediate" "0")])
;; Convert setcc + movzbl to xor + setcc if operands don't overlap.
@ -11791,7 +11801,7 @@
[(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
(match_operand 1))
(unspec [(const_int 0)] UNSPEC_PEEPSIB)]
"!TARGET_X32"
"!TARGET_X32 && !ix86_indirect_branch_register"
"* return ix86_output_call_insn (insn, operands[0]);"
[(set_attr "type" "call")])
@ -11800,7 +11810,9 @@
(match_operand:W 1 "memory_operand"))
(call (mem:QI (match_dup 0))
(match_operand 3))]
"!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
"!TARGET_X32
&& !ix86_indirect_branch_register
&& SIBLING_CALL_P (peep2_next_insn (1))
&& peep2_reg_dead_p (2, operands[0])"
[(parallel [(call (mem:QI (match_dup 1))
(match_dup 3))
@ -11812,7 +11824,9 @@
(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
(call (mem:QI (match_dup 0))
(match_operand 3))]
"!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
"!TARGET_X32
&& !ix86_indirect_branch_register
&& SIBLING_CALL_P (peep2_next_insn (2))
&& peep2_reg_dead_p (3, operands[0])"
[(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
(parallel [(call (mem:QI (match_dup 1))
@ -11833,7 +11847,7 @@
})
(define_insn "*call_pop"
[(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lmBz"))
[(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lBwBz"))
(match_operand 1))
(set (reg:SI SP_REG)
(plus:SI (reg:SI SP_REG)
@ -11853,7 +11867,7 @@
[(set_attr "type" "call")])
(define_insn "*sibcall_pop_memory"
[(call (mem:QI (match_operand:SI 0 "memory_operand" "m"))
[(call (mem:QI (match_operand:SI 0 "memory_operand" "Bs"))
(match_operand 1))
(set (reg:SI SP_REG)
(plus:SI (reg:SI SP_REG)
@ -11905,7 +11919,9 @@
[(set (match_operand:W 0 "register_operand")
(match_operand:W 1 "memory_operand"))
(set (pc) (match_dup 0))]
"!TARGET_X32 && peep2_reg_dead_p (2, operands[0])"
"!TARGET_X32
&& !ix86_indirect_branch_register
&& peep2_reg_dead_p (2, operands[0])"
[(set (pc) (match_dup 1))])
;; Call subroutine, returning value in operand 0
@ -11955,7 +11971,7 @@
(call (mem:QI (match_operand:W 1 "memory_operand" "m"))
(match_operand 2)))
(unspec [(const_int 0)] UNSPEC_PEEPSIB)]
"!TARGET_X32"
"!TARGET_X32 && !ix86_indirect_branch_register"
"* return ix86_output_call_insn (insn, operands[1]);"
[(set_attr "type" "callv")])
@ -11965,7 +11981,9 @@
(set (match_operand 2)
(call (mem:QI (match_dup 0))
(match_operand 3)))]
"!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
"!TARGET_X32
&& !ix86_indirect_branch_register
&& SIBLING_CALL_P (peep2_next_insn (1))
&& peep2_reg_dead_p (2, operands[0])"
[(parallel [(set (match_dup 2)
(call (mem:QI (match_dup 1))
@ -11979,7 +11997,9 @@
(set (match_operand 2)
(call (mem:QI (match_dup 0))
(match_operand 3)))]
"!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
"!TARGET_X32
&& !ix86_indirect_branch_register
&& SIBLING_CALL_P (peep2_next_insn (2))
&& peep2_reg_dead_p (3, operands[0])"
[(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
(parallel [(set (match_dup 2)
@ -12003,7 +12023,7 @@
(define_insn "*call_value_pop"
[(set (match_operand 0)
(call (mem:QI (match_operand:SI 1 "call_insn_operand" "lmBz"))
(call (mem:QI (match_operand:SI 1 "call_insn_operand" "lBwBz"))
(match_operand 2)))
(set (reg:SI SP_REG)
(plus:SI (reg:SI SP_REG)
@ -12196,7 +12216,7 @@
(define_insn "simple_return_internal"
[(simple_return)]
"reload_completed"
"%!ret"
"* return ix86_output_function_return (false);"
[(set_attr "length_nobnd" "1")
(set_attr "atom_unit" "jeu")
(set_attr "length_immediate" "0")
@ -12209,12 +12229,7 @@
[(simple_return)
(unspec [(const_int 0)] UNSPEC_REP)]
"reload_completed"
{
if (ix86_bnd_prefixed_insn_p (insn))
return "%!ret";
return "rep%; ret";
}
"* return ix86_output_function_return (true);"
[(set_attr "length" "2")
(set_attr "atom_unit" "jeu")
(set_attr "length_immediate" "0")
@ -12235,8 +12250,12 @@
[(simple_return)
(use (match_operand:SI 0 "register_operand" "r"))]
"reload_completed"
"%!jmp\t%A0"
[(set_attr "type" "ibr")
"* return ix86_output_indirect_jmp (operands[0], true);"
[(set (attr "type")
(if_then_else (match_test "(cfun->machine->indirect_branch_type
!= indirect_branch_keep)")
(const_string "multi")
(const_string "ibr")))
(set_attr "length_immediate" "0")])
(define_insn "nop"

View File

@ -876,3 +876,31 @@ Enum(stack_protector_guard) String(tls) Value(SSP_TLS)
EnumValue
Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
mindirect-branch=
Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
Convert indirect call and jump to call and return thunks.
mfunction-return=
Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep)
Convert function return to call and return thunk.
Enum
Name(indirect_branch) Type(enum indirect_branch)
Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= options):
EnumValue
Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
EnumValue
Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk)
EnumValue
Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
EnumValue
Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
mindirect-branch-register
Target Report Var(ix86_indirect_branch_register) Init(0)
Force indirect call and jump via register.

View File

@ -607,7 +607,8 @@
;; Test for a valid operand for indirect branch.
(define_predicate "indirect_branch_operand"
(ior (match_operand 0 "register_operand")
(and (not (match_test "TARGET_X32"))
(and (not (match_test "ix86_indirect_branch_register"))
(not (match_test "TARGET_X32"))
(match_operand 0 "memory_operand"))))
;; Test for a valid operand for a call instruction.
@ -616,7 +617,8 @@
(ior (match_test "constant_call_address_operand
(op, mode == VOIDmode ? mode : Pmode)")
(match_operand 0 "call_register_no_elim_operand")
(and (not (match_test "TARGET_X32"))
(and (not (match_test "ix86_indirect_branch_register"))
(not (match_test "TARGET_X32"))
(match_operand 0 "memory_operand"))))
;; Similarly, but for tail calls, in which we cannot allow memory references.
@ -624,7 +626,8 @@
(ior (match_test "constant_call_address_operand
(op, mode == VOIDmode ? mode : Pmode)")
(match_operand 0 "register_no_elim_operand")
(and (not (match_test "TARGET_X32"))
(and (not (match_test "ix86_indirect_branch_register"))
(not (match_test "TARGET_X32"))
(match_operand 0 "sibcall_memory_operand"))))
;; Match exactly zero.

View File

@ -4119,6 +4119,25 @@ Specify which floating-point unit to use. The
@code{target("fpmath=sse,387")} option must be specified as
@code{target("fpmath=sse+387")} because the comma would separate
different options.
@item indirect_branch("@var{choice}")
@cindex @code{indirect_branch} function attribute, x86
On x86 targets, the @code{indirect_branch} attribute causes the compiler
to convert indirect call and jump with @var{choice}. @samp{keep}
keeps indirect call and jump unmodified. @samp{thunk} converts indirect
call and jump to call and return thunk. @samp{thunk-inline} converts
indirect call and jump to inlined call and return thunk.
@samp{thunk-extern} converts indirect call and jump to external call
and return thunk provided in a separate object file.
@item function_return("@var{choice}")
@cindex @code{function_return} function attribute, x86
On x86 targets, the @code{function_return} attribute causes the compiler
to convert function return with @var{choice}. @samp{keep} keeps function
return unmodified. @samp{thunk} converts function return to call and
return thunk. @samp{thunk-inline} converts function return to inlined
call and return thunk. @samp{thunk-extern} converts function return to
external call and return thunk provided in a separate object file.
@end table
On the PowerPC, the following options are allowed:

View File

@ -23214,6 +23214,42 @@ permits the correct alignment of COMMON variables should be
used when generating code. It is enabled by default if
GCC detects that the target assembler found during configuration
supports the feature.
@item -mindirect-branch=@var{choice}
@opindex -mindirect-branch
Convert indirect call and jump with @var{choice}. The default is
@samp{keep}, which keeps indirect call and jump unmodified.
@samp{thunk} converts indirect call and jump to call and return thunk.
@samp{thunk-inline} converts indirect call and jump to inlined call
and return thunk. @samp{thunk-extern} converts indirect call and jump
to external call and return thunk provided in a separate object file.
You can control this behavior for a specific function by using the
function attribute @code{indirect_branch}. @xref{Function Attributes}.
Note that @option{-mcmodel=large} is incompatible with
@option{-mindirect-branch=thunk} nor
@option{-mindirect-branch=thunk-extern} since the thunk function may
not be reachable in large code model.
@item -mfunction-return=@var{choice}
@opindex -mfunction-return
Convert function return with @var{choice}. The default is @samp{keep},
which keeps function return unmodified. @samp{thunk} converts function
return to call and return thunk. @samp{thunk-inline} converts function
return to inlined call and return thunk. @samp{thunk-extern} converts
function return to external call and return thunk provided in a separate
object file. You can control this behavior for a specific function by
using the function attribute @code{function_return}.
@xref{Function Attributes}.
Note that @option{-mcmodel=large} is incompatible with
@option{-mfunction-return=thunk} nor
@option{-mfunction-return=thunk-extern} since the thunk function may
not be reachable in large code model.
@item -mindirect-branch-register
@opindex -mindirect-branch-register
Force indirect call and jump via register.
@end table
See also under @ref{x86 Options} for standard options.