Revert "[ARM] Fix PR85434: spilling of stack protector guard's address on ARM"
This reverts commit r263245. From-SVN: r263252
This commit is contained in:
parent
0016d8d91c
commit
a8b2130aee
11 changed files with 36 additions and 462 deletions
|
@ -89,44 +89,6 @@
|
||||||
(process_file): Move functions processing to
|
(process_file): Move functions processing to
|
||||||
process_all_functions.
|
process_all_functions.
|
||||||
|
|
||||||
2018-08-02 Thomas Preud'homme <thomas.preudhomme@linaro.org>
|
|
||||||
|
|
||||||
PR target/85434
|
|
||||||
* target-insns.def (stack_protect_combined_set): Define new standard
|
|
||||||
pattern name.
|
|
||||||
(stack_protect_combined_test): Likewise.
|
|
||||||
* cfgexpand.c (stack_protect_prologue): Try new
|
|
||||||
stack_protect_combined_set pattern first.
|
|
||||||
* function.c (stack_protect_epilogue): Try new
|
|
||||||
stack_protect_combined_test pattern first.
|
|
||||||
* config/arm/arm.c (require_pic_register): Add pic_reg and compute_now
|
|
||||||
parameters to control which register to use as PIC register and force
|
|
||||||
reloading PIC register respectively. Insert in the stream of insns if
|
|
||||||
possible.
|
|
||||||
(legitimize_pic_address): Expose above new parameters in prototype and
|
|
||||||
adapt recursive calls accordingly.
|
|
||||||
(arm_legitimize_address): Adapt to new legitimize_pic_address
|
|
||||||
prototype.
|
|
||||||
(thumb_legitimize_address): Likewise.
|
|
||||||
(arm_emit_call_insn): Adapt to new require_pic_register prototype.
|
|
||||||
* config/arm/arm-protos.h (legitimize_pic_address): Adapt to prototype
|
|
||||||
change.
|
|
||||||
* config/arm/arm.md (movsi expander): Adapt to legitimize_pic_address
|
|
||||||
prototype change.
|
|
||||||
(stack_protect_combined_set): New insn_and_split pattern.
|
|
||||||
(stack_protect_set): New insn pattern.
|
|
||||||
(stack_protect_combined_test): New insn_and_split pattern.
|
|
||||||
(stack_protect_test): New insn pattern.
|
|
||||||
* config/arm/unspecs.md (UNSPEC_SP_SET): New unspec.
|
|
||||||
(UNSPEC_SP_TEST): Likewise.
|
|
||||||
* doc/md.texi (stack_protect_combined_set): Document new standard
|
|
||||||
pattern name.
|
|
||||||
(stack_protect_set): Clarify that the operand for guard's address is
|
|
||||||
legal.
|
|
||||||
(stack_protect_combined_test): Document new standard pattern name.
|
|
||||||
(stack_protect_test): Clarify that the operand for guard's address is
|
|
||||||
legal.
|
|
||||||
|
|
||||||
2018-08-02 David Malcolm <dmalcolm@redhat.com>
|
2018-08-02 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
* dumpfile.c (dump_user_location_t::dump_user_location_t): Add
|
* dumpfile.c (dump_user_location_t::dump_user_location_t): Add
|
||||||
|
|
|
@ -6105,18 +6105,8 @@ stack_protect_prologue (void)
|
||||||
{
|
{
|
||||||
tree guard_decl = targetm.stack_protect_guard ();
|
tree guard_decl = targetm.stack_protect_guard ();
|
||||||
rtx x, y;
|
rtx x, y;
|
||||||
struct expand_operand ops[2];
|
|
||||||
|
|
||||||
x = expand_normal (crtl->stack_protect_guard);
|
x = expand_normal (crtl->stack_protect_guard);
|
||||||
create_fixed_operand (&ops[0], x);
|
|
||||||
create_fixed_operand (&ops[1], DECL_RTL (guard_decl));
|
|
||||||
/* Allow the target to compute address of Y and copy it to X without
|
|
||||||
leaking Y into a register. This combined address + copy pattern allows
|
|
||||||
the target to prevent spilling of any intermediate results by splitting
|
|
||||||
it after register allocator. */
|
|
||||||
if (maybe_expand_insn (targetm.code_for_stack_protect_combined_set, 2, ops))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (guard_decl)
|
if (guard_decl)
|
||||||
y = expand_normal (guard_decl);
|
y = expand_normal (guard_decl);
|
||||||
else
|
else
|
||||||
|
|
|
@ -67,7 +67,7 @@ extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
|
||||||
extern int arm_split_constant (RTX_CODE, machine_mode, rtx,
|
extern int arm_split_constant (RTX_CODE, machine_mode, rtx,
|
||||||
HOST_WIDE_INT, rtx, rtx, int);
|
HOST_WIDE_INT, rtx, rtx, int);
|
||||||
extern int legitimate_pic_operand_p (rtx);
|
extern int legitimate_pic_operand_p (rtx);
|
||||||
extern rtx legitimize_pic_address (rtx, machine_mode, rtx, rtx, bool);
|
extern rtx legitimize_pic_address (rtx, machine_mode, rtx);
|
||||||
extern rtx legitimize_tls_address (rtx, rtx);
|
extern rtx legitimize_tls_address (rtx, rtx);
|
||||||
extern bool arm_legitimate_address_p (machine_mode, rtx, bool);
|
extern bool arm_legitimate_address_p (machine_mode, rtx, bool);
|
||||||
extern int arm_legitimate_address_outer_p (machine_mode, rtx, RTX_CODE, int);
|
extern int arm_legitimate_address_outer_p (machine_mode, rtx, RTX_CODE, int);
|
||||||
|
|
|
@ -7369,26 +7369,20 @@ legitimate_pic_operand_p (rtx x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record that the current function needs a PIC register. Initialize
|
/* Record that the current function needs a PIC register. Initialize
|
||||||
cfun->machine->pic_reg if we have not already done so.
|
cfun->machine->pic_reg if we have not already done so. */
|
||||||
|
|
||||||
A new pseudo register is used for the PIC register if possible, otherwise
|
|
||||||
PIC_REG must be non NULL and is used instead. COMPUTE_NOW forces the PIC
|
|
||||||
register to be loaded, irregardless of whether it was loaded previously. */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
require_pic_register (rtx pic_reg, bool compute_now)
|
require_pic_register (void)
|
||||||
{
|
{
|
||||||
/* A lot of the logic here is made obscure by the fact that this
|
/* A lot of the logic here is made obscure by the fact that this
|
||||||
routine gets called as part of the rtx cost estimation process.
|
routine gets called as part of the rtx cost estimation process.
|
||||||
We don't want those calls to affect any assumptions about the real
|
We don't want those calls to affect any assumptions about the real
|
||||||
function; and further, we can't call entry_of_function() until we
|
function; and further, we can't call entry_of_function() until we
|
||||||
start the real expansion process. */
|
start the real expansion process. */
|
||||||
if (!crtl->uses_pic_offset_table || compute_now)
|
if (!crtl->uses_pic_offset_table)
|
||||||
{
|
{
|
||||||
gcc_assert (can_create_pseudo_p ()
|
gcc_assert (can_create_pseudo_p ());
|
||||||
|| (pic_reg != NULL_RTX && GET_MODE (pic_reg) == Pmode));
|
|
||||||
if (arm_pic_register != INVALID_REGNUM
|
if (arm_pic_register != INVALID_REGNUM
|
||||||
&& can_create_pseudo_p ()
|
|
||||||
&& !(TARGET_THUMB1 && arm_pic_register > LAST_LO_REGNUM))
|
&& !(TARGET_THUMB1 && arm_pic_register > LAST_LO_REGNUM))
|
||||||
{
|
{
|
||||||
if (!cfun->machine->pic_reg)
|
if (!cfun->machine->pic_reg)
|
||||||
|
@ -7405,8 +7399,7 @@ require_pic_register (rtx pic_reg, bool compute_now)
|
||||||
rtx_insn *seq, *insn;
|
rtx_insn *seq, *insn;
|
||||||
|
|
||||||
if (!cfun->machine->pic_reg)
|
if (!cfun->machine->pic_reg)
|
||||||
cfun->machine->pic_reg =
|
cfun->machine->pic_reg = gen_reg_rtx (Pmode);
|
||||||
can_create_pseudo_p () ? gen_reg_rtx (Pmode) : pic_reg;
|
|
||||||
|
|
||||||
/* Play games to avoid marking the function as needing pic
|
/* Play games to avoid marking the function as needing pic
|
||||||
if we are being called as part of the cost-estimation
|
if we are being called as part of the cost-estimation
|
||||||
|
@ -7417,8 +7410,7 @@ require_pic_register (rtx pic_reg, bool compute_now)
|
||||||
start_sequence ();
|
start_sequence ();
|
||||||
|
|
||||||
if (TARGET_THUMB1 && arm_pic_register != INVALID_REGNUM
|
if (TARGET_THUMB1 && arm_pic_register != INVALID_REGNUM
|
||||||
&& arm_pic_register > LAST_LO_REGNUM
|
&& arm_pic_register > LAST_LO_REGNUM)
|
||||||
&& can_create_pseudo_p ())
|
|
||||||
emit_move_insn (cfun->machine->pic_reg,
|
emit_move_insn (cfun->machine->pic_reg,
|
||||||
gen_rtx_REG (Pmode, arm_pic_register));
|
gen_rtx_REG (Pmode, arm_pic_register));
|
||||||
else
|
else
|
||||||
|
@ -7435,29 +7427,15 @@ require_pic_register (rtx pic_reg, bool compute_now)
|
||||||
we can't yet emit instructions directly in the final
|
we can't yet emit instructions directly in the final
|
||||||
insn stream. Queue the insns on the entry edge, they will
|
insn stream. Queue the insns on the entry edge, they will
|
||||||
be committed after everything else is expanded. */
|
be committed after everything else is expanded. */
|
||||||
if (currently_expanding_to_rtl)
|
insert_insn_on_edge (seq,
|
||||||
insert_insn_on_edge (seq,
|
single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
|
||||||
single_succ_edge
|
|
||||||
(ENTRY_BLOCK_PTR_FOR_FN (cfun)));
|
|
||||||
else
|
|
||||||
emit_insn (seq);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Legitimize PIC load to ORIG into REG. If REG is NULL, a new pseudo is
|
|
||||||
created to hold the result of the load. If not NULL, PIC_REG indicates
|
|
||||||
which register to use as PIC register, otherwise it is decided by register
|
|
||||||
allocator. COMPUTE_NOW forces the PIC register to be loaded at the current
|
|
||||||
location in the instruction stream, irregardless of whether it was loaded
|
|
||||||
previously.
|
|
||||||
|
|
||||||
Returns the register REG into which the PIC load is performed. */
|
|
||||||
|
|
||||||
rtx
|
rtx
|
||||||
legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg,
|
legitimize_pic_address (rtx orig, machine_mode mode, rtx reg)
|
||||||
bool compute_now)
|
|
||||||
{
|
{
|
||||||
if (GET_CODE (orig) == SYMBOL_REF
|
if (GET_CODE (orig) == SYMBOL_REF
|
||||||
|| GET_CODE (orig) == LABEL_REF)
|
|| GET_CODE (orig) == LABEL_REF)
|
||||||
|
@ -7491,7 +7469,7 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg,
|
||||||
rtx mem;
|
rtx mem;
|
||||||
|
|
||||||
/* If this function doesn't have a pic register, create one now. */
|
/* If this function doesn't have a pic register, create one now. */
|
||||||
require_pic_register (pic_reg, compute_now);
|
require_pic_register ();
|
||||||
|
|
||||||
pat = gen_calculate_pic_address (reg, cfun->machine->pic_reg, orig);
|
pat = gen_calculate_pic_address (reg, cfun->machine->pic_reg, orig);
|
||||||
|
|
||||||
|
@ -7542,11 +7520,9 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg,
|
||||||
|
|
||||||
gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
|
gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
|
||||||
|
|
||||||
base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg,
|
base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
|
||||||
pic_reg, compute_now);
|
|
||||||
offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
|
offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
|
||||||
base == reg ? 0 : reg, pic_reg,
|
base == reg ? 0 : reg);
|
||||||
compute_now);
|
|
||||||
|
|
||||||
if (CONST_INT_P (offset))
|
if (CONST_INT_P (offset))
|
||||||
{
|
{
|
||||||
|
@ -8731,8 +8707,7 @@ arm_legitimize_address (rtx x, rtx orig_x, machine_mode mode)
|
||||||
{
|
{
|
||||||
/* We need to find and carefully transform any SYMBOL and LABEL
|
/* We need to find and carefully transform any SYMBOL and LABEL
|
||||||
references; so go back to the original address expression. */
|
references; so go back to the original address expression. */
|
||||||
rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX, NULL_RTX,
|
rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
|
||||||
false /*compute_now*/);
|
|
||||||
|
|
||||||
if (new_x != orig_x)
|
if (new_x != orig_x)
|
||||||
x = new_x;
|
x = new_x;
|
||||||
|
@ -8800,8 +8775,7 @@ thumb_legitimize_address (rtx x, rtx orig_x, machine_mode mode)
|
||||||
{
|
{
|
||||||
/* We need to find and carefully transform any SYMBOL and LABEL
|
/* We need to find and carefully transform any SYMBOL and LABEL
|
||||||
references; so go back to the original address expression. */
|
references; so go back to the original address expression. */
|
||||||
rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX, NULL_RTX,
|
rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
|
||||||
false /*compute_now*/);
|
|
||||||
|
|
||||||
if (new_x != orig_x)
|
if (new_x != orig_x)
|
||||||
x = new_x;
|
x = new_x;
|
||||||
|
@ -18085,7 +18059,7 @@ arm_emit_call_insn (rtx pat, rtx addr, bool sibcall)
|
||||||
? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
|
? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
|
||||||
: !SYMBOL_REF_LOCAL_P (addr)))
|
: !SYMBOL_REF_LOCAL_P (addr)))
|
||||||
{
|
{
|
||||||
require_pic_register (NULL_RTX, false /*compute_now*/);
|
require_pic_register ();
|
||||||
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), cfun->machine->pic_reg);
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), cfun->machine->pic_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6021,8 +6021,7 @@
|
||||||
operands[1] = legitimize_pic_address (operands[1], SImode,
|
operands[1] = legitimize_pic_address (operands[1], SImode,
|
||||||
(!can_create_pseudo_p ()
|
(!can_create_pseudo_p ()
|
||||||
? operands[0]
|
? operands[0]
|
||||||
: NULL_RTX), NULL_RTX,
|
: 0));
|
||||||
false /*compute_now*/);
|
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
)
|
)
|
||||||
|
@ -8635,95 +8634,6 @@
|
||||||
(set_attr "conds" "clob")]
|
(set_attr "conds" "clob")]
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Named patterns for stack smashing protection.
|
|
||||||
(define_insn_and_split "stack_protect_combined_set"
|
|
||||||
[(set (match_operand:SI 0 "memory_operand" "=m")
|
|
||||||
(unspec:SI [(match_operand:SI 1 "memory_operand" "X")]
|
|
||||||
UNSPEC_SP_SET))
|
|
||||||
(match_scratch:SI 2 "=r")
|
|
||||||
(match_scratch:SI 3 "=r")]
|
|
||||||
""
|
|
||||||
"#"
|
|
||||||
"reload_completed"
|
|
||||||
[(parallel [(set (match_dup 0) (unspec:SI [(mem:SI (match_dup 2))]
|
|
||||||
UNSPEC_SP_SET))
|
|
||||||
(clobber (match_dup 2))])]
|
|
||||||
"
|
|
||||||
{
|
|
||||||
rtx addr = XEXP (operands[1], 0);
|
|
||||||
if (flag_pic)
|
|
||||||
{
|
|
||||||
/* Forces recomputing of GOT base now. */
|
|
||||||
operands[1] = legitimize_pic_address (addr, SImode, operands[2],
|
|
||||||
operands[3], true /*compute_now*/);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!address_operand (addr, SImode))
|
|
||||||
operands[1] = force_const_mem (SImode, addr);
|
|
||||||
emit_move_insn (operands[2], operands[1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
|
|
||||||
(define_insn "stack_protect_set"
|
|
||||||
[(set (match_operand:SI 0 "memory_operand" "=m")
|
|
||||||
(unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "r"))]
|
|
||||||
UNSPEC_SP_SET))
|
|
||||||
(clobber (match_dup 1))]
|
|
||||||
""
|
|
||||||
"ldr\\t%1, [%1]\;str\\t%1, %0\;mov\t%1,0"
|
|
||||||
[(set_attr "length" "12")
|
|
||||||
(set_attr "type" "multiple")])
|
|
||||||
|
|
||||||
(define_insn_and_split "stack_protect_combined_test"
|
|
||||||
[(set (pc)
|
|
||||||
(if_then_else
|
|
||||||
(eq (match_operand:SI 0 "memory_operand" "m")
|
|
||||||
(unspec:SI [(match_operand:SI 1 "memory_operand" "X")]
|
|
||||||
UNSPEC_SP_TEST))
|
|
||||||
(label_ref (match_operand 2))
|
|
||||||
(pc)))
|
|
||||||
(match_scratch:SI 3 "=r")
|
|
||||||
(match_scratch:SI 4 "=r")]
|
|
||||||
""
|
|
||||||
"#"
|
|
||||||
"reload_completed"
|
|
||||||
[(const_int 0)]
|
|
||||||
{
|
|
||||||
rtx eq, addr;
|
|
||||||
|
|
||||||
addr = XEXP (operands[1], 0);
|
|
||||||
if (flag_pic)
|
|
||||||
{
|
|
||||||
/* Forces recomputing of GOT base now. */
|
|
||||||
operands[1] = legitimize_pic_address (addr, SImode, operands[3],
|
|
||||||
operands[4],
|
|
||||||
true /*compute_now*/);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!address_operand (addr, SImode))
|
|
||||||
operands[1] = force_const_mem (SImode, addr);
|
|
||||||
emit_move_insn (operands[3], operands[1]);
|
|
||||||
}
|
|
||||||
emit_insn (gen_stack_protect_test (operands[4], operands[0], operands[3]));
|
|
||||||
eq = gen_rtx_EQ (VOIDmode, operands[4], const0_rtx);
|
|
||||||
emit_jump_insn (gen_cbranchsi4 (eq, operands[4], const0_rtx, operands[2]));
|
|
||||||
DONE;
|
|
||||||
})
|
|
||||||
|
|
||||||
(define_insn "stack_protect_test"
|
|
||||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
|
||||||
(unspec:SI [(match_operand:SI 1 "memory_operand" "m")
|
|
||||||
(mem:SI (match_operand:SI 2 "register_operand" "r"))]
|
|
||||||
UNSPEC_SP_TEST))
|
|
||||||
(clobber (match_dup 2))]
|
|
||||||
""
|
|
||||||
"ldr\t%0, [%2]\;ldr\t%2, %1\;eor\t%0, %2, %0"
|
|
||||||
[(set_attr "length" "12")
|
|
||||||
(set_attr "type" "multiple")])
|
|
||||||
|
|
||||||
(define_expand "casesi"
|
(define_expand "casesi"
|
||||||
[(match_operand:SI 0 "s_register_operand" "") ; index to jump on
|
[(match_operand:SI 0 "s_register_operand" "") ; index to jump on
|
||||||
(match_operand:SI 1 "const_int_operand" "") ; lower bound
|
(match_operand:SI 1 "const_int_operand" "") ; lower bound
|
||||||
|
|
|
@ -86,9 +86,6 @@
|
||||||
UNSPEC_PROBE_STACK ; Probe stack memory reference
|
UNSPEC_PROBE_STACK ; Probe stack memory reference
|
||||||
UNSPEC_NONSECURE_MEM ; Represent non-secure memory in ARMv8-M with
|
UNSPEC_NONSECURE_MEM ; Represent non-secure memory in ARMv8-M with
|
||||||
; security extension
|
; security extension
|
||||||
UNSPEC_SP_SET ; Represent the setting of stack protector's canary
|
|
||||||
UNSPEC_SP_TEST ; Represent the testing of stack protector's canary
|
|
||||||
; against the guard.
|
|
||||||
])
|
])
|
||||||
|
|
||||||
(define_c_enum "unspec" [
|
(define_c_enum "unspec" [
|
||||||
|
|
|
@ -7388,61 +7388,22 @@ builtins.
|
||||||
The get/set patterns have a single output/input operand respectively,
|
The get/set patterns have a single output/input operand respectively,
|
||||||
with @var{mode} intended to be @code{Pmode}.
|
with @var{mode} intended to be @code{Pmode}.
|
||||||
|
|
||||||
@cindex @code{stack_protect_combined_set} instruction pattern
|
|
||||||
@item @samp{stack_protect_combined_set}
|
|
||||||
This pattern, if defined, moves a @code{ptr_mode} value from an address
|
|
||||||
whose declaration RTX is given in operand 1 to the memory in operand 0
|
|
||||||
without leaving the value in a register afterward. If several
|
|
||||||
instructions are needed by the target to perform the operation (eg. to
|
|
||||||
load the address from a GOT entry then load the @code{ptr_mode} value
|
|
||||||
and finally store it), it is the backend's responsibility to ensure no
|
|
||||||
intermediate result gets spilled. This is to avoid leaking the value
|
|
||||||
some place that an attacker might use to rewrite the stack guard slot
|
|
||||||
after having clobbered it.
|
|
||||||
|
|
||||||
If this pattern is not defined, then the address declaration is
|
|
||||||
expanded first in the standard way and a @code{stack_protect_set}
|
|
||||||
pattern is then generated to move the value from that address to the
|
|
||||||
address in operand 0.
|
|
||||||
|
|
||||||
@cindex @code{stack_protect_set} instruction pattern
|
@cindex @code{stack_protect_set} instruction pattern
|
||||||
@item @samp{stack_protect_set}
|
@item @samp{stack_protect_set}
|
||||||
This pattern, if defined, moves a @code{ptr_mode} value from the valid
|
This pattern, if defined, moves a @code{ptr_mode} value from the memory
|
||||||
memory location in operand 1 to the memory in operand 0 without leaving
|
in operand 1 to the memory in operand 0 without leaving the value in
|
||||||
the value in a register afterward. This is to avoid leaking the value
|
a register afterward. This is to avoid leaking the value some place
|
||||||
some place that an attacker might use to rewrite the stack guard slot
|
that an attacker might use to rewrite the stack guard slot after
|
||||||
after having clobbered it.
|
having clobbered it.
|
||||||
|
|
||||||
Note: on targets where the addressing modes do not allow to load
|
|
||||||
directly from stack guard address, the address is expanded in a standard
|
|
||||||
way first which could cause some spills.
|
|
||||||
|
|
||||||
If this pattern is not defined, then a plain move pattern is generated.
|
If this pattern is not defined, then a plain move pattern is generated.
|
||||||
|
|
||||||
@cindex @code{stack_protect_combined_test} instruction pattern
|
|
||||||
@item @samp{stack_protect_combined_test}
|
|
||||||
This pattern, if defined, compares a @code{ptr_mode} value from an
|
|
||||||
address whose declaration RTX is given in operand 1 with the memory in
|
|
||||||
operand 0 without leaving the value in a register afterward and
|
|
||||||
branches to operand 2 if the values were equal. If several
|
|
||||||
instructions are needed by the target to perform the operation (eg. to
|
|
||||||
load the address from a GOT entry then load the @code{ptr_mode} value
|
|
||||||
and finally store it), it is the backend's responsibility to ensure no
|
|
||||||
intermediate result gets spilled. This is to avoid leaking the value
|
|
||||||
some place that an attacker might use to rewrite the stack guard slot
|
|
||||||
after having clobbered it.
|
|
||||||
|
|
||||||
If this pattern is not defined, then the address declaration is
|
|
||||||
expanded first in the standard way and a @code{stack_protect_test}
|
|
||||||
pattern is then generated to compare the value from that address to the
|
|
||||||
value at the memory in operand 0.
|
|
||||||
|
|
||||||
@cindex @code{stack_protect_test} instruction pattern
|
@cindex @code{stack_protect_test} instruction pattern
|
||||||
@item @samp{stack_protect_test}
|
@item @samp{stack_protect_test}
|
||||||
This pattern, if defined, compares a @code{ptr_mode} value from the
|
This pattern, if defined, compares a @code{ptr_mode} value from the
|
||||||
valid memory location in operand 1 with the memory in operand 0 without
|
memory in operand 1 with the memory in operand 0 without leaving the
|
||||||
leaving the value in a register afterward and branches to operand 2 if
|
value in a register afterward and branches to operand 2 if the values
|
||||||
the values were equal.
|
were equal.
|
||||||
|
|
||||||
If this pattern is not defined, then a plain compare pattern and
|
If this pattern is not defined, then a plain compare pattern and
|
||||||
conditional branch pattern is used.
|
conditional branch pattern is used.
|
||||||
|
|
|
@ -4893,33 +4893,20 @@ stack_protect_epilogue (void)
|
||||||
rtx_code_label *label = gen_label_rtx ();
|
rtx_code_label *label = gen_label_rtx ();
|
||||||
rtx x, y;
|
rtx x, y;
|
||||||
rtx_insn *seq;
|
rtx_insn *seq;
|
||||||
struct expand_operand ops[3];
|
|
||||||
|
|
||||||
x = expand_normal (crtl->stack_protect_guard);
|
x = expand_normal (crtl->stack_protect_guard);
|
||||||
create_fixed_operand (&ops[0], x);
|
if (guard_decl)
|
||||||
create_fixed_operand (&ops[1], DECL_RTL (guard_decl));
|
y = expand_normal (guard_decl);
|
||||||
create_fixed_operand (&ops[2], label);
|
else
|
||||||
/* Allow the target to compute address of Y and compare it with X without
|
y = const0_rtx;
|
||||||
leaking Y into a register. This combined address + compare pattern allows
|
|
||||||
the target to prevent spilling of any intermediate results by splitting
|
|
||||||
it after register allocator. */
|
|
||||||
if (!maybe_expand_jump_insn (targetm.code_for_stack_protect_combined_test,
|
|
||||||
3, ops))
|
|
||||||
{
|
|
||||||
if (guard_decl)
|
|
||||||
y = expand_normal (guard_decl);
|
|
||||||
else
|
|
||||||
y = const0_rtx;
|
|
||||||
|
|
||||||
/* Allow the target to compare Y with X without leaking either into
|
/* Allow the target to compare Y with X without leaking either into
|
||||||
a register. */
|
a register. */
|
||||||
if (targetm.have_stack_protect_test ()
|
if (targetm.have_stack_protect_test ()
|
||||||
&& ((seq = targetm.gen_stack_protect_test (x, y, label))
|
&& ((seq = targetm.gen_stack_protect_test (x, y, label)) != NULL_RTX))
|
||||||
!= NULL_RTX))
|
emit_insn (seq);
|
||||||
emit_insn (seq);
|
else
|
||||||
else
|
emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
|
||||||
emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The noreturn predictor has been moved to the tree level. The rtl-level
|
/* The noreturn predictor has been moved to the tree level. The rtl-level
|
||||||
predictors estimate this branch about 20%, which isn't enough to get
|
predictors estimate this branch about 20%, which isn't enough to get
|
||||||
|
|
|
@ -96,9 +96,7 @@ DEF_TARGET_INSN (sibcall_value, (rtx x0, rtx x1, rtx opt2, rtx opt3,
|
||||||
DEF_TARGET_INSN (simple_return, (void))
|
DEF_TARGET_INSN (simple_return, (void))
|
||||||
DEF_TARGET_INSN (split_stack_prologue, (void))
|
DEF_TARGET_INSN (split_stack_prologue, (void))
|
||||||
DEF_TARGET_INSN (split_stack_space_check, (rtx x0, rtx x1))
|
DEF_TARGET_INSN (split_stack_space_check, (rtx x0, rtx x1))
|
||||||
DEF_TARGET_INSN (stack_protect_combined_set, (rtx x0, rtx x1))
|
|
||||||
DEF_TARGET_INSN (stack_protect_set, (rtx x0, rtx x1))
|
DEF_TARGET_INSN (stack_protect_set, (rtx x0, rtx x1))
|
||||||
DEF_TARGET_INSN (stack_protect_combined_test, (rtx x0, rtx x1, rtx x2))
|
|
||||||
DEF_TARGET_INSN (stack_protect_test, (rtx x0, rtx x1, rtx x2))
|
DEF_TARGET_INSN (stack_protect_test, (rtx x0, rtx x1, rtx x2))
|
||||||
DEF_TARGET_INSN (store_multiple, (rtx x0, rtx x1, rtx x2))
|
DEF_TARGET_INSN (store_multiple, (rtx x0, rtx x1, rtx x2))
|
||||||
DEF_TARGET_INSN (tablejump, (rtx x0, rtx x1))
|
DEF_TARGET_INSN (tablejump, (rtx x0, rtx x1))
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
PR target/86014
|
PR target/86014
|
||||||
* gcc.target/aarch64/ldp_stp_13.c: New test.
|
* gcc.target/aarch64/ldp_stp_13.c: New test.
|
||||||
|
|
||||||
2018-08-02 Thomas Preud'homme <thomas.preudhomme@linaro.org>
|
|
||||||
|
|
||||||
PR target/85434
|
|
||||||
* gcc.target/arm/pr85434.c: New test.
|
|
||||||
|
|
||||||
2018-08-01 Martin Sebor <msebor@redhat.com>
|
2018-08-01 Martin Sebor <msebor@redhat.com>
|
||||||
|
|
||||||
PR tree-optimization/86650
|
PR tree-optimization/86650
|
||||||
|
|
|
@ -1,200 +0,0 @@
|
||||||
/* { dg-do compile } */
|
|
||||||
/* { dg-require-effective-target fstack_protector }*/
|
|
||||||
/* { dg-require-effective-target fpic }*/
|
|
||||||
/* { dg-additional-options "-Os -fpic -fstack-protector-strong" } */
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
static const unsigned char base64_enc_map[64] =
|
|
||||||
{
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
|
||||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
|
||||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
|
||||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
|
||||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
|
||||||
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
|
|
||||||
'8', '9', '+', '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
|
|
||||||
|
|
||||||
|
|
||||||
void doSmth(void *x);
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
void check(int n) {
|
|
||||||
|
|
||||||
if (!(n % 2 && n % 3 && n % 5)) {
|
|
||||||
__asm__ ( "add r8, r8, #1;" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t test(
|
|
||||||
uint32_t a1,
|
|
||||||
uint32_t a2,
|
|
||||||
size_t a3,
|
|
||||||
size_t a4,
|
|
||||||
size_t a5,
|
|
||||||
size_t a6)
|
|
||||||
{
|
|
||||||
uint32_t nResult = 0;
|
|
||||||
uint8_t* h = 0L;
|
|
||||||
uint8_t X[128];
|
|
||||||
uint8_t mac[64];
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
doSmth(&a1);
|
|
||||||
doSmth(&a2);
|
|
||||||
doSmth(&a3);
|
|
||||||
doSmth(&a4);
|
|
||||||
doSmth(&a5);
|
|
||||||
doSmth(&a6);
|
|
||||||
|
|
||||||
if (a1 && a2 && a3 && a4 && a5 && a6) {
|
|
||||||
nResult = 1;
|
|
||||||
h = (void*)X;
|
|
||||||
len = sizeof(X);
|
|
||||||
memset(X, a2, len);
|
|
||||||
len -= 64;
|
|
||||||
memcpy(mac ,X, len);
|
|
||||||
*(h + len) = a6;
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char *dst = X;
|
|
||||||
size_t dlen = a3;
|
|
||||||
size_t *olen = &a6;
|
|
||||||
const unsigned char *src = mac;
|
|
||||||
size_t slen = a4;
|
|
||||||
size_t i, n;
|
|
||||||
int C1, C2, C3;
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
if( slen == 0 )
|
|
||||||
{
|
|
||||||
*olen = 0;
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
n = slen / 3 + ( slen % 3 != 0 );
|
|
||||||
|
|
||||||
if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
|
|
||||||
{
|
|
||||||
*olen = BASE64_SIZE_T_MAX;
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
n *= 4;
|
|
||||||
|
|
||||||
if( ( dlen < n + 1 ) || ( NULL == dst ) )
|
|
||||||
{
|
|
||||||
*olen = n + 1;
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
n = ( slen / 3 ) * 3;
|
|
||||||
|
|
||||||
for( i = 0, p = dst; i < n; i += 3 )
|
|
||||||
{
|
|
||||||
C1 = *src++;
|
|
||||||
C2 = *src++;
|
|
||||||
C3 = *src++;
|
|
||||||
|
|
||||||
check(i);
|
|
||||||
|
|
||||||
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
|
|
||||||
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
|
|
||||||
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
|
|
||||||
*p++ = base64_enc_map[C3 & 0x3F];
|
|
||||||
}
|
|
||||||
|
|
||||||
if( i < slen )
|
|
||||||
{
|
|
||||||
C1 = *src++;
|
|
||||||
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
|
|
||||||
|
|
||||||
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
|
|
||||||
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
|
|
||||||
|
|
||||||
if( ( i + 1 ) < slen )
|
|
||||||
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
|
|
||||||
else *p++ = '=';
|
|
||||||
|
|
||||||
*p++ = '=';
|
|
||||||
}
|
|
||||||
|
|
||||||
*olen = p - dst;
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
__asm__ ("mov r8, %0;" : "=r" ( nResult ));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nResult = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
doSmth(X);
|
|
||||||
doSmth(mac);
|
|
||||||
|
|
||||||
|
|
||||||
return nResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The pattern below catches sequences of instructions that were generated
|
|
||||||
for ARM and Thumb-2 before the fix for this PR. They are of the form:
|
|
||||||
|
|
||||||
ldr rX, <offset from sp or fp>
|
|
||||||
<optional non ldr instructions>
|
|
||||||
ldr rY, <offset from sp or fp>
|
|
||||||
ldr rZ, [rX]
|
|
||||||
<optional non ldr instructions>
|
|
||||||
cmp rY, rZ
|
|
||||||
<optional non cmp instructions>
|
|
||||||
bl __stack_chk_fail
|
|
||||||
|
|
||||||
Ideally the optional block would check for the various rX, rY and rZ
|
|
||||||
registers not being set but this is not possible due to back references
|
|
||||||
being illegal in lookahead expression in Tcl, thus preventing to use the
|
|
||||||
only construct that allow to negate a regexp from using the backreferences
|
|
||||||
to those registers. Instead we go for the heuristic of allowing non ldr/cmp
|
|
||||||
instructions with the assumptions that (i) those are not part of the stack
|
|
||||||
protector sequences and (ii) they would only be scheduled here if they don't
|
|
||||||
conflict with registers used by stack protector.
|
|
||||||
|
|
||||||
Note on the regexp logic:
|
|
||||||
Allowing non X instructions (where X is ldr or cmp) is done by looking for
|
|
||||||
some non newline spaces, followed by something which is not X, followed by
|
|
||||||
an alphanumeric character followed by anything but a newline and ended by a
|
|
||||||
newline the whole thing an undetermined number of times. The alphanumeric
|
|
||||||
character is there to force the match of the negative lookahead for X to
|
|
||||||
only happen after all the initial spaces and thus to check the mnemonic.
|
|
||||||
This prevents it to match one of the initial space. */
|
|
||||||
/* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\1\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\2, \3(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */
|
|
||||||
|
|
||||||
/* Likewise for Thumb-1 sequences of instructions prior to the fix for this PR
|
|
||||||
which had the form:
|
|
||||||
|
|
||||||
ldr rS, <offset from sp or fp>
|
|
||||||
<optional non ldr instructions>
|
|
||||||
ldr rT, <PC relative offset>
|
|
||||||
<optional non ldr instructions>
|
|
||||||
ldr rX, [rS, rT]
|
|
||||||
<optional non ldr instructions>
|
|
||||||
ldr rY, <offset from sp or fp>
|
|
||||||
ldr rZ, [rX]
|
|
||||||
<optional non ldr instructions>
|
|
||||||
cmp rY, rZ
|
|
||||||
<optional non cmp instructions>
|
|
||||||
bl __stack_chk_fail
|
|
||||||
|
|
||||||
Note on the regexp logic:
|
|
||||||
PC relative offset is checked by looking for a source operand that does not
|
|
||||||
contain [ or ]. */
|
|
||||||
/* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), [^][\n]*(?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[\1, \2\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\3\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\4, \5(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */
|
|
Loading…
Add table
Reference in a new issue