[AArch64, 5/6] Enable BTI : Add new pass for BTI.
authorSudakshina Das <sudi.das@arm.com>
Wed, 9 Jan 2019 14:21:22 +0000 (14:21 +0000)
committerSudakshina Das <sudi@gcc.gnu.org>
Wed, 9 Jan 2019 14:21:22 +0000 (14:21 +0000)
This patch is part of a series that enables ARMv8.5-A in GCC and
adds Branch Target Identification Mechanism.

This patch adds a new pass called "bti" which is triggered by the command
line argument -mbranch-protection whenever "bti" is turned on.

The pass iterates through the instructions and adds appropriated BTI
instructions based on the following:
  * Add a new "BTI C" at the beginning of a function, unless its already
    protected by a "PACIASP". We exempt the functions that are only called
    directly.
  * Add a new "BTI J" for every target of an indirect jump, jump table
    targets, non-local goto targets or labels that might be referenced by
    variables, constant pools, etc (NOTE_INSN_DELETED_LABEL).

Since we have already changed the use of indirect tail calls to only x16 and
x17, we do not have to use "BTI JC".
(check patch 3/6).

*** gcc/ChangeLog ***

2018-01-09  Sudakshina Das  <sudi.das@arm.com>
    Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>

* config.gcc (aarch64*-*-*): Add aarch64-bti-insert.o.
* gcc/config/aarch64/aarch64.h: Update comment for TRAMPOLINE_SIZE.
* config/aarch64/aarch64.c (aarch64_asm_trampoline_template): Update
if bti is enabled.
* config/aarch64/aarch64-bti-insert.c: New file.
* config/aarch64/aarch64-passes.def (INSERT_PASS_BEFORE): Insert bti
pass.
* config/aarch64/aarch64-protos.h (make_pass_insert_bti): Declare the
new bti pass.
* config/aarch64/aarch64.md (unspecv): Add UNSPECV_BTI_NOARG,
UNSPECV_BTI_C, UNSPECV_BTI_J and UNSPECV_BTI_JC.
(bti_noarg, bti_j, bti_c, bti_jc): New define_insns.
* config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.

*** gcc/testsuite/ChangeLog ***

2018-01-09  Sudakshina Das  <sudi.das@arm.com>

* gcc.target/aarch64/bti-1.c: New test.
* gcc.target/aarch64/bti-2.c: New test.
* gcc.target/aarch64/bti-3.c: New test.
* lib/target-supports.exp
(check_effective_target_aarch64_bti_hw): Add new check for BTI hw.

Co-Authored-By: Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
From-SVN: r267769

14 files changed:
gcc/ChangeLog
gcc/config.gcc
gcc/config/aarch64/aarch64-bti-insert.c [new file with mode: 0644]
gcc/config/aarch64/aarch64-passes.def
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.h
gcc/config/aarch64/aarch64.md
gcc/config/aarch64/t-aarch64
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/bti-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/bti-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/bti-3.c [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp

index 0bc36756e4ae74a40b2cae8247c83e4d5b542979..e19b1aecf9b3854b4bdde33c63fde6d14d7bdd4d 100644 (file)
@@ -1,3 +1,20 @@
+2018-01-09  Sudakshina Das  <sudi.das@arm.com>
+           Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+
+       * config.gcc (aarch64*-*-*): Add aarch64-bti-insert.o.
+       * gcc/config/aarch64/aarch64.h: Update comment for TRAMPOLINE_SIZE.
+       * config/aarch64/aarch64.c (aarch64_asm_trampoline_template): Update
+       if bti is enabled.
+       * config/aarch64/aarch64-bti-insert.c: New file.
+       * config/aarch64/aarch64-passes.def (INSERT_PASS_BEFORE): Insert bti
+       pass.
+       * config/aarch64/aarch64-protos.h (make_pass_insert_bti): Declare the
+       new bti pass.
+       * config/aarch64/aarch64.md (unspecv): Add UNSPECV_BTI_NOARG,
+       UNSPECV_BTI_C, UNSPECV_BTI_J and UNSPECV_BTI_JC.
+       (bti_noarg, bti_j, bti_c, bti_jc): New define_insns.
+       * config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.
+
 2018-01-09  Sudakshina Das  <sudi.das@arm.com>
 
        * config/aarch64/aarch64-protos.h (aarch64_bti_enabled): Declare.
index 3f5a37dc8db08fc33a664c0cc008790accbe71a9..f7ddb120ee2522110e534b519450038512689066 100644 (file)
@@ -318,7 +318,7 @@ aarch64*-*-*)
        c_target_objs="aarch64-c.o"
        cxx_target_objs="aarch64-c.o"
        d_target_objs="aarch64-d.o"
-       extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o"
+       extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o"
        target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c"
        target_has_targetm_common=yes
        ;;
diff --git a/gcc/config/aarch64/aarch64-bti-insert.c b/gcc/config/aarch64/aarch64-bti-insert.c
new file mode 100644 (file)
index 0000000..e519a0f
--- /dev/null
@@ -0,0 +1,235 @@
+/* Branch Target Identification for AArch64 architecture.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by Arm Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#define INCLUDE_STRING
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "memmodel.h"
+#include "gimple.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "emit-rtl.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "dumpfile.h"
+#include "rtl-iter.h"
+#include "cfgrtl.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+
+/* This pass enables the support for Branch Target Identification Mechanism
+   for AArch64.  This is a new security feature introduced in ARMv8.5-A
+   archtitecture.  A BTI instruction is used to guard against the execution
+   of instructions which are not the intended target of an indirect branch.
+
+   Outside of a guarded memory region, a BTI instruction executes as a NOP.
+   Within a guarded memory region any target of an indirect branch must be
+   a compatible BTI or BRK, HLT, PACIASP, PACIBASP instruction (even if the
+   branch is triggered in a non-guarded memory region).  An incompatibility
+   generates a Branch Target Exception.
+
+   The compatibility of the BTI instruction is as follows:
+   BTI j : Can be a target of any indirect jump (BR Xn).
+   BTI c : Can be a target of any indirect call (BLR Xn and BR X16/X17).
+   BTI jc: Can be a target of any indirect call or indirect jump.
+   BTI   : Can not be a target of any indirect call or indirect jump.
+
+  In order to enable this mechanism, this pass iterates through the
+  control flow of the code and adds appropriate BTI instructions :
+  * Add a new "BTI C" at the beginning of a function, unless its already
+    protected by a "PACIASP/PACIBSP".  We exempt the functions that are only
+    called directly.
+  * Add a new "BTI J" for every target of an indirect jump, jump table targets,
+    non-local goto targets or labels that might be referenced by variables,
+    constant pools, etc (NOTE_INSN_DELETED_LABEL)
+
+  Since we have already changed the use of indirect tail calls to only x16
+  and x17, we do not have to use "BTI JC".
+
+  This pass is triggered by the command line option -mbranch-protection=bti or
+  -mbranch-protection=standard.  Since all the BTI instructions are in the HINT
+  space, this pass does not require any minimum architecture version.  */
+
+namespace {
+
+const pass_data pass_data_insert_bti =
+{
+  RTL_PASS, /* type.  */
+  "bti", /* name.  */
+  OPTGROUP_NONE, /* optinfo_flags.  */
+  TV_MACH_DEP, /* tv_id.  */
+  0, /* properties_required.  */
+  0, /* properties_provided.  */
+  0, /* properties_destroyed.  */
+  0, /* todo_flags_start.  */
+  0, /* todo_flags_finish.  */
+};
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction.  */
+static bool
+aarch64_pac_insn_p (rtx x)
+{
+  if (!INSN_P (x))
+    return x;
+
+  subrtx_var_iterator::array_type array;
+  FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (x), ALL)
+    {
+      rtx sub = *iter;
+      if (sub && GET_CODE (sub) == UNSPEC)
+       {
+         int unspec_val = XINT (sub, 1);
+         switch (unspec_val)
+           {
+           case UNSPEC_PACISP:
+             return true;
+
+           default:
+             return false;
+           }
+         iter.skip_subrtxes ();
+       }
+    }
+  return false;
+}
+
+/* Insert the BTI instruction.  */
+/* This is implemented as a late RTL pass that runs before branch
+   shortening and does the following.  */
+static unsigned int
+rest_of_insert_bti (void)
+{
+  timevar_push (TV_MACH_DEP);
+
+  rtx bti_insn;
+  rtx_insn *insn;
+  basic_block bb;
+
+  /* Since a Branch Target Exception can only be triggered by an indirect call,
+     we exempt function that are only called directly.  We also exempt
+     functions that are already protected by Return Address Signing (PACIASP/
+     PACIBSP).  For all other cases insert a BTI C at the beginning of the
+     function.  */
+  if (!cgraph_node::get (cfun->decl)->only_called_directly_p ())
+    {
+      bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
+      insn = BB_HEAD (bb);
+      if (!aarch64_pac_insn_p (get_first_nonnote_insn ()))
+       {
+         bti_insn = gen_bti_c ();
+         emit_insn_before (bti_insn, insn);
+       }
+    }
+
+  bb = 0;
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
+          insn = NEXT_INSN (insn))
+       {
+         /* If a label is marked to be preserved or can be a non-local goto
+            target, it must be protected with a BTI J.  The same applies to
+            NOTE_INSN_DELETED_LABEL since they are basically labels that might
+            be referenced via variables or constant pool.  */
+         if ((LABEL_P (insn)
+              && (LABEL_PRESERVE_P (insn)
+                  || bb->flags & BB_NON_LOCAL_GOTO_TARGET))
+             || (NOTE_P (insn)
+                 && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))
+           {
+             bti_insn = gen_bti_j ();
+             emit_insn_after (bti_insn, insn);
+             continue;
+           }
+
+         /* There could still be more labels that are valid targets of a
+            BTI J instuction.  To find them we start looking through the
+            JUMP_INSN.  If it jumps to a jump table, then we find all labels
+            of the jump table to protect with a BTI J.  */
+         if (JUMP_P (insn))
+           {
+             rtx_jump_table_data *table;
+             if (tablejump_p (insn, NULL, &table))
+               {
+                 rtvec vec = table->get_labels ();
+                 int j;
+                 rtx_insn *label;
+
+                 for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
+                   {
+                     label = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, j), 0));
+                     bti_insn = gen_bti_j ();
+                     emit_insn_after (bti_insn, label);
+                   }
+               }
+           }
+
+         /* Also look for calls to setjmp () which would be marked with
+            REG_SETJMP note and put a BTI J after.  This is where longjump ()
+            will return.  */
+         if (CALL_P (insn) && (find_reg_note (insn, REG_SETJMP, NULL)))
+           {
+             bti_insn = gen_bti_j ();
+             emit_insn_after (bti_insn, insn);
+             continue;
+           }
+       }
+    }
+
+  timevar_pop (TV_MACH_DEP);
+  return 0;
+}
+
+
+class pass_insert_bti : public rtl_opt_pass
+{
+public:
+  pass_insert_bti (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_insert_bti, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return aarch64_bti_enabled ();
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_insert_bti ();
+    }
+
+}; // class pass_insert_bti
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_insert_bti (gcc::context *ctxt)
+{
+  return new pass_insert_bti (ctxt);
+}
index d554c8b7312bec4723b946d987ee35411fe15cc0..12d1ad6ba39dbaa6a0278b13a67f5421d434b3e3 100644 (file)
@@ -21,3 +21,4 @@
 INSERT_PASS_AFTER (pass_regrename, 1, pass_fma_steering);
 INSERT_PASS_BEFORE (pass_reorder_blocks, 1, pass_track_speculation);
 INSERT_PASS_AFTER (pass_machine_reorg, 1, pass_tag_collision_avoidance);
+INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_bti);
index 3e3ad14d3232c68c9988a47795e23a474eaf8421..b035e35f33ba86ceb7b0255e7e0e9ad2d69bf829 100644 (file)
@@ -633,6 +633,7 @@ extern void aarch64_d_target_versions (void);
 rtl_opt_pass *make_pass_fma_steering (gcc::context *);
 rtl_opt_pass *make_pass_track_speculation (gcc::context *);
 rtl_opt_pass *make_pass_tag_collision_avoidance (gcc::context *);
+rtl_opt_pass *make_pass_insert_bti (gcc::context *ctxt);
 
 poly_uint64 aarch64_regmode_natural_size (machine_mode);
 
index 47569b841f9d51ed58c49615fbfc9ae09107ef2f..d5e140dd08a85457eef8ad2a1ee7717f5cbc76ac 100644 (file)
@@ -8250,18 +8250,36 @@ aarch64_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
 static void
 aarch64_asm_trampoline_template (FILE *f)
 {
+  int offset1 = 16;
+  int offset2 = 20;
+
+  if (aarch64_bti_enabled ())
+    {
+      asm_fprintf (f, "\thint\t34 // bti c\n");
+      offset1 -= 4;
+      offset2 -= 4;
+    }
+
   if (TARGET_ILP32)
     {
-      asm_fprintf (f, "\tldr\tw%d, .+16\n", IP1_REGNUM - R0_REGNUM);
-      asm_fprintf (f, "\tldr\tw%d, .+16\n", STATIC_CHAIN_REGNUM - R0_REGNUM);
+      asm_fprintf (f, "\tldr\tw%d, .+%d\n", IP1_REGNUM - R0_REGNUM, offset1);
+      asm_fprintf (f, "\tldr\tw%d, .+%d\n", STATIC_CHAIN_REGNUM - R0_REGNUM,
+                  offset1);
     }
   else
     {
-      asm_fprintf (f, "\tldr\t%s, .+16\n", reg_names [IP1_REGNUM]);
-      asm_fprintf (f, "\tldr\t%s, .+20\n", reg_names [STATIC_CHAIN_REGNUM]);
+      asm_fprintf (f, "\tldr\t%s, .+%d\n", reg_names [IP1_REGNUM], offset1);
+      asm_fprintf (f, "\tldr\t%s, .+%d\n", reg_names [STATIC_CHAIN_REGNUM],
+                  offset2);
     }
   asm_fprintf (f, "\tbr\t%s\n", reg_names [IP1_REGNUM]);
-  assemble_aligned_integer (4, const0_rtx);
+
+  /* The trampoline needs an extra padding instruction.  In case if BTI is
+     enabled the padding instruction is replaced by the BTI instruction at
+     the beginning.  */
+  if (!aarch64_bti_enabled ())
+    assemble_aligned_integer (4, const0_rtx);
+
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
 }
index e401ffb1962d20963810e8971f7ae189d450169c..63f3be7fff47675634e9c037415da54b050fba34 100644 (file)
@@ -918,7 +918,7 @@ typedef struct
 
 #define RETURN_ADDR_RTX aarch64_return_addr
 
-/* 3 insns + padding + 2 pointer-sized entries.  */
+/* BTI c + 3 insns + 2 pointer-sized entries.  */
 #define TRAMPOLINE_SIZE        (TARGET_ILP32 ? 24 : 32)
 
 /* Trampolines contain dwords, so must be dword aligned.  */
index 1d8226d3efa4cb34b382806efebba1d2954fd13f..513aec1872a7a5d29233d0bcb0bd1331d306eaaf 100644 (file)
     UNSPECV_BLOCKAGE           ; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE  ; Represent stack range probing.
     UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
+    UNSPECV_BTI_NOARG          ; Represent BTI.
+    UNSPECV_BTI_C              ; Represent BTI c.
+    UNSPECV_BTI_J              ; Represent BTI j.
+    UNSPECV_BTI_JC             ; Represent BTI jc.
   ]
 )
 
   [(set_attr "type" "csel")]
 )
 
+;; BTI <target> instructions
+(define_insn "bti_noarg"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_NOARG)]
+  ""
+  "hint\t32 // bti"
+  [(set_attr "type" "no_insn")]
+)
+
+(define_insn "bti_c"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_C)]
+  ""
+  "hint\t34 // bti c"
+  [(set_attr "type" "no_insn")]
+)
+
+(define_insn "bti_j"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_J)]
+  ""
+  "hint\t36 // bti j"
+  [(set_attr "type" "no_insn")]
+)
+
+(define_insn "bti_jc"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_JC)]
+  ""
+  "hint\t38 // bti jc"
+  [(set_attr "type" "no_insn")]
+)
+
 ;; Helper for aarch64.c code.
 (define_expand "set_clobber_cc"
   [(parallel [(set (match_operand 0)
index caae1f671f2119d9b767b21fce7d140e715651ba..ee471f8983f2afb1f1198a60c95d9df662fbad90 100644 (file)
@@ -91,6 +91,15 @@ falkor-tag-collision-avoidance.o: \
        $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
                $(srcdir)/config/aarch64/falkor-tag-collision-avoidance.c
 
+aarch64-bti-insert.o: $(srcdir)/config/aarch64/aarch64-bti-insert.c \
+    $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(REGS_H) insn-config.h $(RTL_BASE_H) \
+    dominance.h cfg.h cfganal.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(RECOG_H) \
+    output.h hash-map.h $(DF_H) $(OBSTACK_H) $(TARGET_H) $(RTL_H) \
+    $(CONTEXT_H) $(TREE_PASS_H) regrename.h \
+    $(srcdir)/config/aarch64/aarch64-protos.h
+       $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+               $(srcdir)/config/aarch64/aarch64-bti-insert.c
+
 comma=,
 MULTILIB_OPTIONS    = $(subst $(comma),/, $(patsubst %, mabi=%, $(subst $(comma),$(comma)mabi=,$(TM_MULTILIB_CONFIG))))
 MULTILIB_DIRNAMES   = $(subst $(comma), ,$(TM_MULTILIB_CONFIG))
index d3d73f54eae7d7183da4f6d0cbc1198a0e0429de..b55a7abd83e196aa7205360f748b8f36e3d45be9 100644 (file)
@@ -1,3 +1,11 @@
+2018-01-09  Sudakshina Das  <sudi.das@arm.com>
+
+       * gcc.target/aarch64/bti-1.c: New test.
+       * gcc.target/aarch64/bti-2.c: New test.
+       * gcc.target/aarch64/bti-3.c: New test.
+       * lib/target-supports.exp
+       (check_effective_target_aarch64_bti_hw): Add new check for BTI hw.
+
 2018-01-09  Sudakshina Das  <sudi.das@arm.com>
 
        * gcc.target/aarch64/test_frame_17.c: Update to check for EP0_REGNUM
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-1.c b/gcc/testsuite/gcc.target/aarch64/bti-1.c
new file mode 100644 (file)
index 0000000..575d01a
--- /dev/null
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* -Os to create jump table.  */
+/* { dg-options "-Os -mbranch-protection=standard" } */
+
+extern int f1 (void);
+extern int f2 (void);
+extern int f3 (void);
+extern int f4 (void);
+extern int f5 (void);
+extern int f6 (void);
+extern int f7 (void);
+extern int f8 (void);
+extern int f9 (void);
+extern int f10 (void);
+
+int (*ptr) (void);
+
+int
+f_jump_table (int y, int n)
+{
+  int i;
+  for (i = 0; i < n ;i ++)
+  {
+    switch (y)
+      {
+      case 0 : ptr = f1; break;
+      case 1 : ptr = f2; break;
+      case 2 : ptr = f3; break;
+      case 3 : ptr = f4; break;
+      case 4 : ptr = f5; break;
+      case 5 : ptr = f6; break;
+      case 6 : ptr = f7; break;
+      case 7 : ptr = f8; break;
+      case 8 : ptr = f9; break;
+      case 9 : ptr = f10; break;
+      default: break;
+      }
+    y += ptr ();
+  }
+  return (y == 0)? y+1:4;
+}
+/* f_jump_table should have PACIASP and AUTIASP.  */
+/* { dg-final { scan-assembler-times "hint\t25" 1 } } */
+/* { dg-final { scan-assembler-times "hint\t29" 1 } } */
+
+int
+f_label_address ()
+{
+  static void * addr = &&lab1;
+  goto *addr;
+lab1:
+  addr = &&lab2;
+  return 1;
+lab2:
+  addr = &&lab1;
+  return 2;
+}
+/* { dg-final { scan-assembler-times "hint\t34" 1 } } */
+/* { dg-final { scan-assembler-times "hint\t36" 12 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-2.c b/gcc/testsuite/gcc.target/aarch64/bti-2.c
new file mode 100644 (file)
index 0000000..e50eef1
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-require-effective-target aarch64_bti_hw } */
+/* { dg-options "-mbranch-protection=standard" } */
+
+#include<stdio.h>
+
+typedef int FP (int);
+
+int
+f1 (FP fp, int n)
+{
+  return (fp) (n);
+}
+
+int
+f2 (int n, FP fp)
+{
+  return (fp) (n);
+}
+
+int __attribute__ ((noinline))
+func (int x)
+{
+  return x+1;
+}
+
+int main ()
+{
+  int s = 0;
+  s += f1 (func, 10);
+  s += f2 (s, func);
+  printf ("S: %d\n", s);
+  return !(s == 23);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-3.c b/gcc/testsuite/gcc.target/aarch64/bti-3.c
new file mode 100644 (file)
index 0000000..97cf5d3
--- /dev/null
@@ -0,0 +1,52 @@
+/* This is a copy of gcc/testsuite/gcc.c-torture/execute/pr56982.c to test the
+   setjmp case of the bti pass.  */
+/* { dg-do run } */
+/* { dg-require-effective-target aarch64_bti_hw } */
+/* { dg-options "--save-temps -mbranch-protection=standard" } */
+
+#include <setjmp.h>
+
+extern void abort (void);
+extern void exit (int);
+
+static jmp_buf env;
+
+void baz (void)
+{
+  __asm__ volatile ("" : : : "memory");
+}
+
+static inline int g(int x)
+{
+    if (x)
+    {
+        baz();
+        return 0;
+    }
+    else
+    {
+        baz();
+        return 1;
+    }
+}
+
+int f(int *e)
+{
+    if (*e)
+      return 1;
+
+    int x = setjmp(env);
+    int n = g(x);
+    if (n == 0)
+      exit(0);
+    if (x)
+      abort();
+    longjmp(env, 42);
+}
+/* { dg-final { scan-assembler "hint\t36" } } */
+
+int main(int argc, char** argv)
+{
+    int v = 0;
+    return f(&v);
+}
index a9bb6b3bdc6c9706af0d679bd0a154d779624913..d694f495493fa014b053f406529d6bef4d67c46e 100644 (file)
@@ -4313,6 +4313,22 @@ proc check_effective_target_arm_neonv2_hw { } {
     } [add_options_for_arm_neonv2 ""]]
 }
 
+# ID_AA64PFR1_EL1.BT using bits[3:0] == 1 implies BTI implimented.
+proc check_effective_target_aarch64_bti_hw { } {
+    if { ![istarget aarch64*-*-*] } {
+       return 0
+    }
+    return [check_runtime aarch64_bti_hw_available {
+       int
+       main (void)
+       {
+         int a;
+         asm volatile ("mrs %0, id_aa64pfr1_el1" : "=r" (a));
+         return !((a & 0xf) == 1);
+       }
+    } "-O2" ]
+}
+
 # Return 1 if the target supports the ARMv8.1 Adv.SIMD extension, 0
 # otherwise.  The test is valid for AArch64 and ARM.  Record the command
 # line options needed.