[AArch64] Add support for system register based stack protector canary access
authorRamana Radhakrishnan <ramana.radhakrishnan@arm.com>
Fri, 18 Jan 2019 10:32:40 +0000 (10:32 +0000)
committerRamana Radhakrishnan <ramana@gcc.gnu.org>
Fri, 18 Jan 2019 10:32:40 +0000 (10:32 +0000)
2019-01-18  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>

        * config/aarch64/aarch64-opts.h (enum stack_protector_guard): New
        * config/aarch64/aarch64.c (aarch64_override_options_internal): Handle
        and put in error checks for stack protector guard options.
        (aarch64_stack_protect_guard): New.
        (TARGET_STACK_PROTECT_GUARD): Define.
        * config/aarch64/aarch64.md (UNSPEC_SSP_SYSREG): New.
        (reg_stack_protect_address<mode>): New.
        (stack_protect_set): Adjust for SSP_GLOBAL.
        (stack_protect_test): Likewise.
        * config/aarch64/aarch64.opt (-mstack-protector-guard-reg): New.
        (-mstack-protector-guard): Likewise.
        (-mstack-protector-guard-offset): Likewise.

From-SVN: r268068

gcc/ChangeLog
gcc/config/aarch64/aarch64-opts.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.md
gcc/config/aarch64/aarch64.opt
gcc/doc/invoke.texi

index a16deb681537ec392445630e42d779c3b08e214e..6dbff4b08213540f20efc31a9391c9f372ad10cd 100644 (file)
@@ -1,3 +1,18 @@
+2019-01-18  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+
+        * config/aarch64/aarch64-opts.h (enum stack_protector_guard): New
+        * config/aarch64/aarch64.c (aarch64_override_options_internal): Handle
+        and put in error checks for stack protector guard options.
+        (aarch64_stack_protect_guard): New.
+        (TARGET_STACK_PROTECT_GUARD): Define.
+        * config/aarch64/aarch64.md (UNSPEC_SSP_SYSREG): New.
+        (reg_stack_protect_address<mode>): New.
+        (stack_protect_set): Adjust for SSP_GLOBAL.
+        (stack_protect_test): Likewise.
+        * config/aarch64/aarch64.opt (-mstack-protector-guard-reg): New.
+        (-mstack-protector-guard): Likewise.
+        (-mstack-protector-guard-offset): Likewise.
+
 2019-01-18  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/86214
index 7982de1f5c6cdc2ba79ced1680b1ff968a543053..4b07d296a115933d9da87272dd65e90cd90bd10f 100644 (file)
@@ -92,4 +92,10 @@ enum aarch64_sve_vector_bits_enum {
   SVE_2048 = 2048
 };
 
+/* Where to get the canary for the stack protector.  */
+enum stack_protector_guard {
+  SSP_SYSREG,                  /* per-thread canary in special system register */
+  SSP_GLOBAL                   /* global canary */
+};
+
 #endif
index 7eb9316d4666eb7c80ce8c3eddd97e8792e6c9dd..e13badaf6cf90cc9c9d121db86ac5161277d8c3f 100644 (file)
@@ -11409,6 +11409,41 @@ aarch64_override_options_internal (struct gcc_options *opts)
   if (opts->x_flag_strict_volatile_bitfields < 0 && abi_version_at_least (2))
     opts->x_flag_strict_volatile_bitfields = 1;
 
+  if (aarch64_stack_protector_guard == SSP_GLOBAL
+      && opts->x_aarch64_stack_protector_guard_offset_str)
+    {
+      error ("incompatible options -mstack-protector-guard=global and"
+            "-mstack-protector-guard-offset=%qs",
+            aarch64_stack_protector_guard_offset_str);
+    }
+
+  if (aarch64_stack_protector_guard == SSP_SYSREG
+      && !(opts->x_aarch64_stack_protector_guard_offset_str
+          && opts->x_aarch64_stack_protector_guard_reg_str))
+    {
+      error ("both -mstack-protector-guard-offset and "
+            "-mstack-protector-guard-reg must be used "
+            "with -mstack-protector-guard=sysreg");
+    }
+
+  if (opts->x_aarch64_stack_protector_guard_reg_str)
+    {
+      if (strlen (opts->x_aarch64_stack_protector_guard_reg_str) > 100)
+         error ("specify a system register with a small string length.");
+    }
+
+  if (opts->x_aarch64_stack_protector_guard_offset_str)
+    {
+      char *end;
+      const char *str = aarch64_stack_protector_guard_offset_str;
+      errno = 0;
+      long offs = strtol (aarch64_stack_protector_guard_offset_str, &end, 0);
+      if (!*str || *end || errno)
+       error ("%qs is not a valid offset in %qs", str,
+              "-mstack-protector-guard-offset=");
+      aarch64_stack_protector_guard_offset = offs;
+    }
+
   initialize_aarch64_code_model (opts);
   initialize_aarch64_tls_size (opts);
 
@@ -18671,8 +18706,24 @@ aarch64_run_selftests (void)
 
 } // namespace selftest
 
+/* Implement TARGET_STACK_PROTECT_GUARD. In case of a
+   global variable based guard use the default else
+   return a null tree.  */
+static tree
+aarch64_stack_protect_guard (void)
+{
+  if (aarch64_stack_protector_guard == SSP_GLOBAL)
+    return default_stack_protect_guard ();
+
+  return NULL_TREE;
+}
+
+
 #endif /* #if CHECKING_P */
 
+#undef TARGET_STACK_PROTECT_GUARD
+#define TARGET_STACK_PROTECT_GUARD aarch64_stack_protect_guard
+
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST aarch64_address_cost
 
index 522c7748443cb2ed9d3a744d8e2c7a04f323f61f..b7f6fe0f1354f7aa19076a946ed2c633b9b9b8da 100644 (file)
     UNSPEC_UCVTF
     UNSPEC_USHL_2S
     UNSPEC_VSTRUCTDUMMY
+    UNSPEC_SSP_SYSREG
     UNSPEC_SP_SET
     UNSPEC_SP_TEST
     UNSPEC_RSQRT
   ""
 {
   machine_mode mode = GET_MODE (operands[0]);
+  if (aarch64_stack_protector_guard != SSP_GLOBAL)
+  {
+    /* Generate access through the system register.  */
+    rtx tmp_reg = gen_reg_rtx (mode);
+    if (mode == DImode)
+    {
+        emit_insn (gen_reg_stack_protect_address_di (tmp_reg));
+        emit_insn (gen_adddi3 (tmp_reg, tmp_reg,
+                              GEN_INT (aarch64_stack_protector_guard_offset)));
+    }
+    else
+    {
+       emit_insn (gen_reg_stack_protect_address_si (tmp_reg));
+       emit_insn (gen_addsi3 (tmp_reg, tmp_reg,
+                              GEN_INT (aarch64_stack_protector_guard_offset)));
 
+    }
+    operands[1] = gen_rtx_MEM (mode, tmp_reg);
+  }
+  
   emit_insn ((mode == DImode
              ? gen_stack_protect_set_di
              : gen_stack_protect_set_si) (operands[0], operands[1]));
   DONE;
 })
 
+(define_insn "reg_stack_protect_address_<mode>"
+ [(set (match_operand:PTR 0 "register_operand" "=r")
+       (unspec:PTR [(const_int 0)]
+       UNSPEC_SSP_SYSREG))]
+ "aarch64_stack_protector_guard != SSP_GLOBAL"
+ {
+   char buf[150];
+   snprintf (buf, 150, "mrs\\t%%<w>0, %s",
+           aarch64_stack_protector_guard_reg_str);
+   output_asm_insn (buf, operands);
+   return "";
+ }
+ [(set_attr "type" "mrs")])
+
 (define_insn "stack_protect_set_<mode>"
   [(set (match_operand:PTR 0 "memory_operand" "=m")
        (unspec:PTR [(match_operand:PTR 1 "memory_operand" "m")]
   machine_mode mode = GET_MODE (operands[0]);
 
   result = gen_reg_rtx(mode);
+  if (aarch64_stack_protector_guard != SSP_GLOBAL)
+  {
+    /* Generate access through the system register. The
+       sequence we want here is the access
+       of the stack offset to come with
+       mrs scratch_reg, <system_register>
+       add scratch_reg, scratch_reg, :lo12:offset. */
+    rtx tmp_reg = gen_reg_rtx (mode);
+    if (mode == DImode)
+    {
+       emit_insn (gen_reg_stack_protect_address_di (tmp_reg));
+       emit_insn (gen_adddi3 (tmp_reg, tmp_reg,
+                                     GEN_INT (aarch64_stack_protector_guard_offset)));
+    }
+    else
+    {
+       emit_insn (gen_reg_stack_protect_address_si (tmp_reg));
+       emit_insn (gen_addsi3 (tmp_reg, tmp_reg,
+                              GEN_INT (aarch64_stack_protector_guard_offset)));
 
+    }
+    operands[1] = gen_rtx_MEM (mode, tmp_reg);
+  }
   emit_insn ((mode == DImode
-             ? gen_stack_protect_test_di
-             : gen_stack_protect_test_si) (result,
-                                           operands[0],
-                                           operands[1]));
+                 ? gen_stack_protect_test_di
+                 : gen_stack_protect_test_si) (result,
+                                               operands[0],
+                                               operands[1]));
 
   if (mode == DImode)
     emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
index 6de7b225f22d99e16fa7fb43fe7fbce6257f9043..5a1e687091cc3265bbaa5993251a8da0650abc40 100644 (file)
@@ -225,3 +225,33 @@ Enables verbose cost model dumping in the debug dump files.
 mtrack-speculation
 Target Var(aarch64_track_speculation)
 Generate code to track when the CPU might be speculating incorrectly.
+
+mstack-protector-guard=
+Target RejectNegative Joined Enum(stack_protector_guard) Var(aarch64_stack_protector_guard) Init(SSP_GLOBAL)
+Use given stack-protector guard.
+
+Enum
+Name(stack_protector_guard) Type(enum stack_protector_guard)
+Valid arguments to -mstack-protector-guard=:
+
+EnumValue
+Enum(stack_protector_guard) String(sysreg) Value(SSP_SYSREG)
+
+EnumValue
+Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
+
+mstack-protector-guard-reg=
+Target Joined RejectNegative String Var(aarch64_stack_protector_guard_reg_str)
+Use the system register specified on the command line as the stack protector
+guard register. This option is for use with fstack-protector-strong and
+not for use in user-land code.
+
+mstack-protector-guard-offset=
+Target Joined RejectNegative String Var(aarch64_stack_protector_guard_offset_str)
+Use an immediate to offset from the stack protector guard register, sp_el0.
+This option is for use with fstack-protector-strong and not for use in
+user-land code.
+
+TargetVariable
+long aarch64_stack_protector_guard_offset = 0
+
index 1151708aaf083788aa9c5830cdb93f55b3d888e7..9997dcb7bb22f895780f8faf335083a066b32218 100644 (file)
@@ -633,7 +633,9 @@ Objective-C and Objective-C++ Dialects}.
 -msign-return-address=@var{scope} @gol
 -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}] @gol
 -march=@var{name}  -mcpu=@var{name}  -mtune=@var{name}  @gol
--moverride=@var{string}  -mverbose-cost-dump  -mtrack-speculation} 
+-moverride=@var{string}  -mverbose-cost-dump @gol
+-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{sysreg} @gol
+-mstack-protector-guard-offset=@var{offset} -mtrack-speculation }
 
 @emph{Adapteva Epiphany Options}
 @gccoptlist{-mhalf-reg-file  -mprefer-short-insn-regs @gol
@@ -15606,6 +15608,42 @@ object boundary as described in the architecture specification.
 Omit or keep the frame pointer in leaf functions.  The former behavior is the
 default.
 
+@item -mstack-protector-guard=@var{guard}
+@itemx -mstack-protector-guard-reg=@var{reg}
+@itemx -mstack-protector-guard-offset=@var{offset}
+@opindex mstack-protector-guard
+@opindex mstack-protector-guard-reg
+@opindex mstack-protector-guard-offset
+Generate stack protection code using canary at @var{guard}.  Supported
+locations are @samp{global} for a global canary or @samp{sysreg} for a
+canary in an appropriate system register.
+
+With the latter choice the options
+@option{-mstack-protector-guard-reg=@var{reg}} and
+@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
+which system register to use as base register for reading the canary,
+and from what offset from that base register. There is no default
+register or offset as this is entirely for use within the Linux
+kernel.
+
+@item -mstack-protector-guard=@var{guard}
+@itemx -mstack-protector-guard-reg=@var{reg}
+@itemx -mstack-protector-guard-offset=@var{offset}
+@opindex mstack-protector-guard
+@opindex mstack-protector-guard-reg
+@opindex mstack-protector-guard-offset
+Generate stack protection code using canary at @var{guard}.  Supported
+locations are @samp{global} for a global canary or @samp{sysreg} for a
+canary in an appropriate system register.
+
+With the latter choice the options
+@option{-mstack-protector-guard-reg=@var{reg}} and
+@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
+which system register to use as base register for reading the canary,
+and from what offset from that base register. There is no default
+register or offset as this is entirely for use within the Linux
+kernel.
+
 @item -mtls-dialect=desc
 @opindex mtls-dialect=desc
 Use TLS descriptors as the thread-local storage mechanism for dynamic accesses