diff mbox series

[AARCH64,5/6] Enable BTI : Add new pass for BTI.

Message ID f99c2918-0d71-271f-6a70-156f8d02486b@arm.com
State New
Headers show
Series [AARCH64,1/6] Enable ARMv8.5-A in gcc | expand

Commit Message

Sudakshina Das Nov. 2, 2018, 6:38 p.m. UTC
Hi

This patch is part of a series that enables ARMv8.5-A in GCC and
adds Branch Target Identification Mechanism.
(https://developer.arm.com/products/architecture/cpu-architecture/a-profile/exploration-tools)

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/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".
(check patch 3/6).

Bootstrapped and regression tested with aarch64-none-linux-gnu. Added 
new tests.
Is this ok for trunk?

Thanks
Sudi

*** gcc/ChangeLog ***

2018-xx-xx  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 (bti_nop): Define.
	* config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.

*** gcc/testsuite/ChangeLog ***

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

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

Comments

Sudakshina Das Nov. 13, 2018, 2:47 p.m. UTC | #1
Hi

On 02/11/18 18:38, Sudakshina Das wrote:
> Hi
> 
> This patch is part of a series that enables ARMv8.5-A in GCC and
> adds Branch Target Identification Mechanism.
> (https://developer.arm.com/products/architecture/cpu-architecture/a-profile/exploration-tools)
> 
> 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/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".
> (check patch 3/6).
> 

I missed out on the explanation for the changes to the trampoline code.
The patch also updates the trampoline code in case BTI is enabled. Since
the trampoline code is a target of an indirect branch, we need to add an
appropriate BTI instruction at the beginning of it to avoid a branch
target exception.

> Bootstrapped and regression tested with aarch64-none-linux-gnu. Added
> new tests.
> Is this ok for trunk?
> 
> Thanks
> Sudi
> 
> *** gcc/ChangeLog ***
> 
> 2018-xx-xx  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 (bti_nop): Define.
> 	* config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.
> 
> *** gcc/testsuite/ChangeLog ***
> 
> 2018-xx-xx  Sudakshina Das  <sudi.das@arm.com>
> 
> 	* gcc.target/aarch64/bti-1.c: New test.
> 	* gcc.target/aarch64/bti-2.c: New test.
> 	* lib/target-supports.exp
> 	(check_effective_target_aarch64_bti_hw): Add new check for
> 	BTI hw.
>

Updated patch attached with more comments and a bit of simplification
in aarch64-bti-insert.c. ChangeLog still applies.

Thanks
Sudi
diff --git a/gcc/config.gcc b/gcc/config.gcc
index b108697cfc7b1c9c6dc1f30cca6fd1158182c29e..3e77f9df6ad6ca55fccca50387eab4b2501af647 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -317,7 +317,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
index 0000000000000000000000000000000000000000..15202e0def3b514bdbd1564b39a121e43e01a67f
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-bti-insert.c
@@ -0,0 +1,226 @@
+/* Branch Target Identification for AArch64 architecture.
+   Copyright (C) 2018 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_PACIASP:
+	    case UNSPEC_PACIBSP:
+	      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_nop (GEN_INT (INSN_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_nop (GEN_INT (INSN_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_nop (GEN_INT (INSN_BTI_J));
+		      emit_insn_after (bti_insn, label);
+		    }
+		}
+	    }
+	}
+    }
+
+  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);
+}
diff --git a/gcc/config/aarch64/aarch64-passes.def b/gcc/config/aarch64/aarch64-passes.def
index 3982b6ea6290379e6ecac8046ebb27a14d2342f0..d3e316f406ecb0119787a67ad1c62fafaaf99a88 100644
--- a/gcc/config/aarch64/aarch64-passes.def
+++ b/gcc/config/aarch64/aarch64-passes.def
@@ -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);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index a5ccfe534b6c59c90bd91215f89c59d67fd88688..5adbfe28ba37a56b1daf05a96f30ae9584a1780d 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -400,6 +400,15 @@ enum aarch64_key_type {
 
 extern enum aarch64_key_type aarch64_ra_sign_key;
 
+/* Enum for HINT values for BTI instructions.  */
+enum bti_insn_type
+{
+  INSN_BTI_NOARG	= 32,
+  INSN_BTI_C		= 34,
+  INSN_BTI_J		= 36,
+  INSN_BTI_JC		= 38
+};
+
 extern struct tune_params aarch64_tune_params;
 
 void aarch64_post_cfi_startproc (void);
@@ -636,6 +645,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);
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index cc95be32d40268d3647c8280188f17ff8212a156..bd82ae3ddea4979e64608e0dc8b9d969fb691cd4 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -925,7 +925,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.  */
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index fa12f9cc6bcc99e021ef579839bbac7715558855..b97d9e4deecf5ca33761dfd1008c39bb4b849881 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -8070,18 +8070,33 @@ 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\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);
+
+  if (!aarch64_bti_enabled ())
+    assemble_aligned_integer (4, const0_rtx);
+
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
 }
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 3ca6d61e7e28b780f94bf5080b126dac60fe0524..30693ce83fea1ccc6ee5e4aad1f0f0cd9b44f47a 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -240,6 +240,7 @@
     UNSPECV_BLOCKAGE		; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE	; Represent stack range probing.
     UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
+    UNSPECV_BTI_NOP		; Represent a BTI instruction.
   ]
 )
 
@@ -6720,6 +6721,40 @@
   [(set_attr "type" "csel")]
 )
 
+(define_insn "bti_nop"
+  [(unspec_volatile [(match_operand:SI 0 "const_int_operand")]
+    UNSPECV_BTI_NOP)]
+  ""
+  {
+   char buf[100];
+   bti_insn_type val = (bti_insn_type) INTVAL (operands[0]);
+   switch (val)
+    {
+      case INSN_BTI_NOARG:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti");
+	break;
+
+      case INSN_BTI_C:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti c");
+	break;
+
+      case INSN_BTI_J:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti j");
+	break;
+
+      case INSN_BTI_JC:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti jc");
+	break;
+
+      default:
+	gcc_unreachable ();
+    }
+    output_asm_insn (buf, operands);
+    return "";
+   }
+  [(set_attr "type" "no_insn")]
+)
+
 ;; Helper for aarch64.c code.
 (define_expand "set_clobber_cc"
   [(parallel [(set (match_operand 0)
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index e91dccea9954c2c387fb111d1b357dd2c220ff0a..a2048547be56eba8a47c22c9d2b94e787364828f 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -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))
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-1.c b/gcc/testsuite/gcc.target/aarch64/bti-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..575d01a5411a19dabcdb56b777e5d87d9703a848
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-1.c
@@ -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
index 0000000000000000000000000000000000000000..e50eef15c8936d00716c582e90b235add5da9136
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-2.c
@@ -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/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index fd74c04d092b0e2341b85eefbebb1f0df9423492..65ff16817f5f88255148bb69d7018975465197dc 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4270,6 +4270,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.
Sudakshina Das Nov. 29, 2018, 4:47 p.m. UTC | #2
Hi

On 13/11/18 14:47, Sudakshina Das wrote:
> Hi
> 
> On 02/11/18 18:38, Sudakshina Das wrote:
>> Hi
>>
>> This patch is part of a series that enables ARMv8.5-A in GCC and
>> adds Branch Target Identification Mechanism.
>> (https://developer.arm.com/products/architecture/cpu-architecture/a-profile/exploration-tools)
>>
>> 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/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".
>> (check patch 3/6).
>>
> 
> I missed out on the explanation for the changes to the trampoline code.
> The patch also updates the trampoline code in case BTI is enabled. Since
> the trampoline code is a target of an indirect branch, we need to add an
> appropriate BTI instruction at the beginning of it to avoid a branch
> target exception.
> 
>> Bootstrapped and regression tested with aarch64-none-linux-gnu. Added
>> new tests.
>> Is this ok for trunk?
>>
>> Thanks
>> Sudi
>>
>> *** gcc/ChangeLog ***
>>
>> 2018-xx-xx  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 (bti_nop): Define.
>> 	* config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.
>>
>> *** gcc/testsuite/ChangeLog ***
>>
>> 2018-xx-xx  Sudakshina Das  <sudi.das@arm.com>
>>
>> 	* gcc.target/aarch64/bti-1.c: New test.
>> 	* gcc.target/aarch64/bti-2.c: New test.
>> 	* lib/target-supports.exp
>> 	(check_effective_target_aarch64_bti_hw): Add new check for
>> 	BTI hw.
>>
> 
> Updated patch attached with more comments and a bit of simplification
> in aarch64-bti-insert.c. ChangeLog still applies.
> 
> Thanks
> Sudi
> 

I found a missed case in the bti pass and edited the patch to include
it. This made me realize that the only 2 regressions I saw with the
BTI enabled model can now be avoided. (as quoted below from my 6/6
patch)
"Bootstrapped and regression tested with aarch64-none-linux-gnu with
and without the configure option turned on.
Also tested on aarch64-none-elf with and without configure option with a
BTI enabled aem. Only 2 regressions and these were because newlib
requires patches to protect hand coded libraries with BTI."

The ChangeLog still applies.

Sudi
diff --git a/gcc/config.gcc b/gcc/config.gcc
index b108697cfc7b1c9c6dc1f30cca6fd1158182c29e..3e77f9df6ad6ca55fccca50387eab4b2501af647 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -317,7 +317,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
index 0000000000000000000000000000000000000000..be604fb2fd5df052971cc81b7e6d7760880a6b79
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-bti-insert.c
@@ -0,0 +1,236 @@
+/* Branch Target Identification for AArch64 architecture.
+   Copyright (C) 2018 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_PACIASP:
+	    case UNSPEC_PACIBSP:
+	      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_nop (GEN_INT (INSN_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_nop (GEN_INT (INSN_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_nop (GEN_INT (INSN_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_nop (GEN_INT (INSN_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);
+}
diff --git a/gcc/config/aarch64/aarch64-passes.def b/gcc/config/aarch64/aarch64-passes.def
index 3982b6ea6290379e6ecac8046ebb27a14d2342f0..d3e316f406ecb0119787a67ad1c62fafaaf99a88 100644
--- a/gcc/config/aarch64/aarch64-passes.def
+++ b/gcc/config/aarch64/aarch64-passes.def
@@ -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);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index a5ccfe534b6c59c90bd91215f89c59d67fd88688..5adbfe28ba37a56b1daf05a96f30ae9584a1780d 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -400,6 +400,15 @@ enum aarch64_key_type {
 
 extern enum aarch64_key_type aarch64_ra_sign_key;
 
+/* Enum for HINT values for BTI instructions.  */
+enum bti_insn_type
+{
+  INSN_BTI_NOARG	= 32,
+  INSN_BTI_C		= 34,
+  INSN_BTI_J		= 36,
+  INSN_BTI_JC		= 38
+};
+
 extern struct tune_params aarch64_tune_params;
 
 void aarch64_post_cfi_startproc (void);
@@ -636,6 +645,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);
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index cc95be32d40268d3647c8280188f17ff8212a156..bd82ae3ddea4979e64608e0dc8b9d969fb691cd4 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -925,7 +925,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.  */
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index fa12f9cc6bcc99e021ef579839bbac7715558855..b97d9e4deecf5ca33761dfd1008c39bb4b849881 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -8070,18 +8070,33 @@ 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\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);
+
+  if (!aarch64_bti_enabled ())
+    assemble_aligned_integer (4, const0_rtx);
+
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
 }
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 3ca6d61e7e28b780f94bf5080b126dac60fe0524..30693ce83fea1ccc6ee5e4aad1f0f0cd9b44f47a 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -240,6 +240,7 @@
     UNSPECV_BLOCKAGE		; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE	; Represent stack range probing.
     UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
+    UNSPECV_BTI_NOP		; Represent a BTI instruction.
   ]
 )
 
@@ -6720,6 +6721,40 @@
   [(set_attr "type" "csel")]
 )
 
+(define_insn "bti_nop"
+  [(unspec_volatile [(match_operand:SI 0 "const_int_operand")]
+    UNSPECV_BTI_NOP)]
+  ""
+  {
+   char buf[100];
+   bti_insn_type val = (bti_insn_type) INTVAL (operands[0]);
+   switch (val)
+    {
+      case INSN_BTI_NOARG:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti");
+	break;
+
+      case INSN_BTI_C:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti c");
+	break;
+
+      case INSN_BTI_J:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti j");
+	break;
+
+      case INSN_BTI_JC:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti jc");
+	break;
+
+      default:
+	gcc_unreachable ();
+    }
+    output_asm_insn (buf, operands);
+    return "";
+   }
+  [(set_attr "type" "no_insn")]
+)
+
 ;; Helper for aarch64.c code.
 (define_expand "set_clobber_cc"
   [(parallel [(set (match_operand 0)
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index e91dccea9954c2c387fb111d1b357dd2c220ff0a..a2048547be56eba8a47c22c9d2b94e787364828f 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -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))
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-1.c b/gcc/testsuite/gcc.target/aarch64/bti-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..575d01a5411a19dabcdb56b777e5d87d9703a848
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-1.c
@@ -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
index 0000000000000000000000000000000000000000..e50eef15c8936d00716c582e90b235add5da9136
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-2.c
@@ -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/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index fd74c04d092b0e2341b85eefbebb1f0df9423492..65ff16817f5f88255148bb69d7018975465197dc 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4270,6 +4270,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.
Sudakshina Das Dec. 14, 2018, 4:09 p.m. UTC | #3
Hi James

On 29/11/18 16:47, Sudakshina Das wrote:
> Hi
> 
> On 13/11/18 14:47, Sudakshina Das wrote:
>> Hi
>>
>> On 02/11/18 18:38, Sudakshina Das wrote:
>>> Hi
>>>
>>> This patch is part of a series that enables ARMv8.5-A in GCC and
>>> adds Branch Target Identification Mechanism.
>>> (https://developer.arm.com/products/architecture/cpu-architecture/a-profile/exploration-tools)
>>>
>>> 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/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".
>>> (check patch 3/6).
>>>
>>
>> I missed out on the explanation for the changes to the trampoline code.
>> The patch also updates the trampoline code in case BTI is enabled. Since
>> the trampoline code is a target of an indirect branch, we need to add an
>> appropriate BTI instruction at the beginning of it to avoid a branch
>> target exception.
>>
>>> Bootstrapped and regression tested with aarch64-none-linux-gnu. Added
>>> new tests.
>>> Is this ok for trunk?
>>>
>>> Thanks
>>> Sudi
>>>
>>> *** gcc/ChangeLog ***
>>>
>>> 2018-xx-xx  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 (bti_nop): Define.
>>> 	* config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>>
>>> 2018-xx-xx  Sudakshina Das  <sudi.das@arm.com>
>>>
>>> 	* gcc.target/aarch64/bti-1.c: New test.
>>> 	* gcc.target/aarch64/bti-2.c: New test.
>>> 	* lib/target-supports.exp
>>> 	(check_effective_target_aarch64_bti_hw): Add new check for
>>> 	BTI hw.
>>>
>>
>> Updated patch attached with more comments and a bit of simplification
>> in aarch64-bti-insert.c. ChangeLog still applies.
>>
>> Thanks
>> Sudi
>>
> 
> I found a missed case in the bti pass and edited the patch to include
> it. This made me realize that the only 2 regressions I saw with the
> BTI enabled model can now be avoided. (as quoted below from my 6/6
> patch)
> "Bootstrapped and regression tested with aarch64-none-linux-gnu with
> and without the configure option turned on.
> Also tested on aarch64-none-elf with and without configure option with a
> BTI enabled aem. Only 2 regressions and these were because newlib
> requires patches to protect hand coded libraries with BTI."
> 
> The ChangeLog still applies.
> 
> Sudi
> 
I have updated the patch according to our discussions offline.
The md pattern is now split into 4 patterns and i have added a new
test for the setjmp case along with some comments where missing.

*** gcc/ChangeLog ***

2018-xx-xx  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-xx-xx  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.

Thanks
Sudi
diff --git a/gcc/config.gcc b/gcc/config.gcc
index cbabd21b33723a65790e2eafe8aa4979051cae48..f3dd3feceb3375374a29ca58e4ad87f949cea44d 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -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
index 0000000000000000000000000000000000000000..b8ab3f7bf64aa8f0071a911c9019eb0a78d45ead
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-bti-insert.c
@@ -0,0 +1,236 @@
+/* Branch Target Identification for AArch64 architecture.
+   Copyright (C) 2018 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_PACIASP:
+	    case UNSPEC_PACIBSP:
+	      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);
+}
diff --git a/gcc/config/aarch64/aarch64-passes.def b/gcc/config/aarch64/aarch64-passes.def
index 3982b6ea6290379e6ecac8046ebb27a14d2342f0..d3e316f406ecb0119787a67ad1c62fafaaf99a88 100644
--- a/gcc/config/aarch64/aarch64-passes.def
+++ b/gcc/config/aarch64/aarch64-passes.def
@@ -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);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index fa1128ce9b7208d732059feee48ebf3a0039850c..210c5d88c53ab34bae343237788dfe0d0cd80a4a 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -635,6 +635,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);
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index cc95be32d40268d3647c8280188f17ff8212a156..bd82ae3ddea4979e64608e0dc8b9d969fb691cd4 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -925,7 +925,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.  */
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 8262e9da03683793995408fd8caf90dc069e1c8d..f66c963dcd5b00138c6a96cb013b675d639698e4 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -8137,18 +8137,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);
 }
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 1f21cbdd8e7e74c7f1183a85976d160b09d3049a..86f246b53c53908f555e5b844ad8b90b794a6fee 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -240,6 +240,10 @@
     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.
   ]
 )
 
@@ -6721,6 +6725,35 @@
   [(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)
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index e91dccea9954c2c387fb111d1b357dd2c220ff0a..a2048547be56eba8a47c22c9d2b94e787364828f 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -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))
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-1.c b/gcc/testsuite/gcc.target/aarch64/bti-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..575d01a5411a19dabcdb56b777e5d87d9703a848
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-1.c
@@ -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
index 0000000000000000000000000000000000000000..e50eef15c8936d00716c582e90b235add5da9136
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-2.c
@@ -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
index 0000000000000000000000000000000000000000..97cf5d37f42b9313da75481c2ceac884735ac995
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-3.c
@@ -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);
+}
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 5026c5906cda3f2f1b21afbc9cd270aee1a81129..85b3b83776e2f8966a0ba3c6d1903bbd4995de52 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -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.
James Greenhalgh Dec. 19, 2018, 3:40 p.m. UTC | #4
On Fri, Dec 14, 2018 at 10:09:03AM -0600, Sudakshina Das wrote:

<snip>

> I have updated the patch according to our discussions offline.
> The md pattern is now split into 4 patterns and i have added a new
> test for the setjmp case along with some comments where missing.

This is OK for trunk.

Thanks,
James

> *** gcc/ChangeLog ***
> 
> 2018-xx-xx  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-xx-xx  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.
> 
> Thanks
> Sudi
Sudakshina Das Dec. 20, 2018, 4:40 p.m. UTC | #5
Hi James

On 19/12/18 3:40 PM, James Greenhalgh wrote:
> On Fri, Dec 14, 2018 at 10:09:03AM -0600, Sudakshina Das wrote:
> 
> <snip>
> 
>> I have updated the patch according to our discussions offline.
>> The md pattern is now split into 4 patterns and i have added a new
>> test for the setjmp case along with some comments where missing.
> 
> This is OK for trunk.
> 

Thanks for the approvals. With this my series is ready to go in trunk. I 
will wait for Sam's options patch to go in trunk before I commit mine.

Thanks
Sudi

> Thanks,
> James
> 
>> *** gcc/ChangeLog ***
>>
>> 2018-xx-xx  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-xx-xx  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.
>>
>> Thanks
>> Sudi
Sudakshina Das Jan. 9, 2019, 2:42 p.m. UTC | #6
Hi

On 20/12/18 16:40, Sudakshina Das wrote:
> Hi James
> 
> On 19/12/18 3:40 PM, James Greenhalgh wrote:
>> On Fri, Dec 14, 2018 at 10:09:03AM -0600, Sudakshina Das wrote:
>>
>> <snip>
>>
>>> I have updated the patch according to our discussions offline.
>>> The md pattern is now split into 4 patterns and i have added a new
>>> test for the setjmp case along with some comments where missing.
>>
>> This is OK for trunk.
>>
> 
> Thanks for the approvals. With this my series is ready to go in trunk. I 
> will wait for Sam's options patch to go in trunk before I commit mine.
> 

Series is committed with a rebase without Sam Tebbs's 3rd patch for 
B-Key addition as r267765 to r267770.

Thanks
Sudi

> Thanks
> Sudi
> 
>> Thanks,
>> James
>>
>>> *** gcc/ChangeLog ***
>>>
>>> 2018-xx-xx  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-xx-xx  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.
>>>
>>> Thanks
>>> Sudi
Christophe Lyon Jan. 10, 2019, 3:46 p.m. UTC | #7
On Wed, 9 Jan 2019 at 15:42, Sudakshina Das <Sudi.Das@arm.com> wrote:
>
> Hi
>
> On 20/12/18 16:40, Sudakshina Das wrote:
> > Hi James
> >
> > On 19/12/18 3:40 PM, James Greenhalgh wrote:
> >> On Fri, Dec 14, 2018 at 10:09:03AM -0600, Sudakshina Das wrote:
> >>
> >> <snip>
> >>
> >>> I have updated the patch according to our discussions offline.
> >>> The md pattern is now split into 4 patterns and i have added a new
> >>> test for the setjmp case along with some comments where missing.
> >>
> >> This is OK for trunk.
> >>
> >
> > Thanks for the approvals. With this my series is ready to go in trunk. I
> > will wait for Sam's options patch to go in trunk before I commit mine.
> >
>
> Series is committed with a rebase without Sam Tebbs's 3rd patch for
> B-Key addition as r267765 to r267770.
>
> Thanks
> Sudi
>

Hi Sudi,

I think the new bti-1.c test lacks
/* { dg-require-effective-target lp64 } */
as I see it failing when using -mabi=ilp32:
cc1: sorry, unimplemented: return address signing is only supported
for -mabi=lp64

Christophe

> > Thanks
> > Sudi
> >
> >> Thanks,
> >> James
> >>
> >>> *** gcc/ChangeLog ***
> >>>
> >>> 2018-xx-xx  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-xx-xx  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.
> >>>
> >>> Thanks
> >>> Sudi
>
Sudakshina Das Jan. 10, 2019, 4:54 p.m. UTC | #8
Hi Christophe

On 10/01/19 15:46, Christophe Lyon wrote:
> On Wed, 9 Jan 2019 at 15:42, Sudakshina Das <Sudi.Das@arm.com> wrote:
>>
>> Hi
>>
>> On 20/12/18 16:40, Sudakshina Das wrote:
>>> Hi James
>>>
>>> On 19/12/18 3:40 PM, James Greenhalgh wrote:
>>>> On Fri, Dec 14, 2018 at 10:09:03AM -0600, Sudakshina Das wrote:
>>>>
>>>> <snip>
>>>>
>>>>> I have updated the patch according to our discussions offline.
>>>>> The md pattern is now split into 4 patterns and i have added a new
>>>>> test for the setjmp case along with some comments where missing.
>>>>
>>>> This is OK for trunk.
>>>>
>>>
>>> Thanks for the approvals. With this my series is ready to go in trunk. I
>>> will wait for Sam's options patch to go in trunk before I commit mine.
>>>
>>
>> Series is committed with a rebase without Sam Tebbs's 3rd patch for
>> B-Key addition as r267765 to r267770.
>>
>> Thanks
>> Sudi
>>
> 
> Hi Sudi,
> 
> I think the new bti-1.c test lacks
> /* { dg-require-effective-target lp64 } */
> as I see it failing when using -mabi=ilp32:
> cc1: sorry, unimplemented: return address signing is only supported
> for -mabi=lp64
> 

Ah yes, I actually added code for exempting ilp32 in my configure patch 
but missed it while adding test cases. Testing a patch right now.

Sudi

> Christophe
> 
>>> Thanks
>>> Sudi
>>>
>>>> Thanks,
>>>> James
>>>>
>>>>> *** gcc/ChangeLog ***
>>>>>
>>>>> 2018-xx-xx  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-xx-xx  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.
>>>>>
>>>>> Thanks
>>>>> Sudi
>>
Andrew Pinski Aug. 18, 2022, midnight UTC | #9
On Fri, Nov 2, 2018 at 11:39 AM Sudakshina Das <Sudi.Das@arm.com> wrote:
>
> Hi
>
> This patch is part of a series that enables ARMv8.5-A in GCC and
> adds Branch Target Identification Mechanism.
> (https://developer.arm.com/products/architecture/cpu-architecture/a-profile/exploration-tools)
>
> 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/PACIBSP". We exempt the functions that are
>       only called directly.

Coming back to this because the check only_called_directly_p does not
work if the linker will insert a veneer as the compiler does not know
about that.
This is recorded as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671 .

Thanks,
Andrew Pinski


>     * 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).
>
> Bootstrapped and regression tested with aarch64-none-linux-gnu. Added
> new tests.
> Is this ok for trunk?
>
> Thanks
> Sudi
>
> *** gcc/ChangeLog ***
>
> 2018-xx-xx  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 (bti_nop): Define.
>         * config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2018-xx-xx  Sudakshina Das  <sudi.das@arm.com>
>
>         * gcc.target/aarch64/bti-1.c: New test.
>         * gcc.target/aarch64/bti-2.c: New test.
>         * lib/target-supports.exp
>         (check_effective_target_aarch64_bti_hw): Add new check for
>         BTI hw.
>
Richard Earnshaw Aug. 18, 2022, 10:10 a.m. UTC | #10
On 18/08/2022 01:00, Andrew Pinski via Gcc-patches wrote:
> On Fri, Nov 2, 2018 at 11:39 AM Sudakshina Das <Sudi.Das@arm.com> wrote:
>>
>> Hi
>>
>> This patch is part of a series that enables ARMv8.5-A in GCC and
>> adds Branch Target Identification Mechanism.
>> (https://developer.arm.com/products/architecture/cpu-architecture/a-profile/exploration-tools)
>>
>> 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/PACIBSP". We exempt the functions that are
>>        only called directly.
> 
> Coming back to this because the check only_called_directly_p does not
> work if the linker will insert a veneer as the compiler does not know
> about that.
> This is recorded as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671 .

I think the linker has to make sure to insert a veneer that ends with a 
branch in that case.

R.

> 
> Thanks,
> Andrew Pinski
> 
> 
>>      * 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).
>>
>> Bootstrapped and regression tested with aarch64-none-linux-gnu. Added
>> new tests.
>> Is this ok for trunk?
>>
>> Thanks
>> Sudi
>>
>> *** gcc/ChangeLog ***
>>
>> 2018-xx-xx  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 (bti_nop): Define.
>>          * config/aarch64/t-aarch64: Add rule for aarch64-bti-insert.o.
>>
>> *** gcc/testsuite/ChangeLog ***
>>
>> 2018-xx-xx  Sudakshina Das  <sudi.das@arm.com>
>>
>>          * gcc.target/aarch64/bti-1.c: New test.
>>          * gcc.target/aarch64/bti-2.c: New test.
>>          * lib/target-supports.exp
>>          (check_effective_target_aarch64_bti_hw): Add new check for
>>          BTI hw.
>>
diff mbox series

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index b108697cfc7b1c9c6dc1f30cca6fd1158182c29e..3e77f9df6ad6ca55fccca50387eab4b2501af647 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -317,7 +317,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
index 0000000000000000000000000000000000000000..efd57620d8803302e03ca643b9f2495e188dc19b
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-bti-insert.c
@@ -0,0 +1,195 @@ 
+/* Branch Target Identification for AArch64 architecture.
+   Copyright (C) 2018 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"
+
+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_PACIASP:
+	    case UNSPEC_PACIBSP:
+	      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;
+
+  /* Exempt function that are only called directly.  */
+  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_nop (GEN_INT (INSN_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 ((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_nop (GEN_INT (INSN_BTI_J));
+	      emit_insn_after (bti_insn, insn);
+	      continue;
+	    }
+
+	  if (JUMP_P (insn))
+	    {
+	      rtx target = JUMP_LABEL (insn);
+	      if (target == NULL_RTX || ANY_RETURN_P (target))
+		continue;
+
+	      /* Check the jump is a switch table.  */
+	      rtx_insn *label = as_a<rtx_insn *> (target);
+	      rtx_insn *table = next_insn (label);
+	      if (table == NULL_RTX || !JUMP_TABLE_DATA_P (table))
+		continue;
+
+	      /* For the indirect jump find out all places it jumps and insert
+		 a BTI instruction there.  */
+	      edge_iterator ei;
+	      edge e;
+	      basic_block dest_blk;
+
+	      FOR_EACH_EDGE (e, ei, bb->succs)
+		{
+		  rtx_insn *insn;
+
+		  dest_blk = e->dest;
+		  insn = BB_HEAD (dest_blk);
+		  gcc_assert (LABEL_P (insn));
+		  bti_insn = gen_bti_nop (GEN_INT (INSN_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);
+}
diff --git a/gcc/config/aarch64/aarch64-passes.def b/gcc/config/aarch64/aarch64-passes.def
index 3982b6ea6290379e6ecac8046ebb27a14d2342f0..d3e316f406ecb0119787a67ad1c62fafaaf99a88 100644
--- a/gcc/config/aarch64/aarch64-passes.def
+++ b/gcc/config/aarch64/aarch64-passes.def
@@ -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);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 913b63efb5eec3c7b600d9fb18b4a6c5e41d1fc5..1767356c5ef2c82d337acc14260d2d38b448a6f2 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -401,6 +401,15 @@  enum aarch64_key_type {
 
 extern enum aarch64_key_type aarch64_ra_sign_key;
 
+/* Enum for HINT values for BTI instructions.  */
+enum bti_insn_type
+{
+  INSN_BTI_NOARG	= 32,
+  INSN_BTI_C		= 34,
+  INSN_BTI_J		= 36,
+  INSN_BTI_JC		= 38
+};
+
 extern struct tune_params aarch64_tune_params;
 
 void aarch64_post_cfi_startproc (void);
@@ -637,6 +646,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);
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 34938b4271d167873d689cc8e4c2be9a00981434..09d76b5737b552abceba36634594050770f4e6cc 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -924,7 +924,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.  */
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index f60cf9d5b023503013dd0ac3e13e0d0e883a66e3..12a55a640de4fdc5df21d313c7ea6841f1daf3f2 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -8049,18 +8049,33 @@  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\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);
+
+  if (!aarch64_bti_enabled ())
+    assemble_aligned_integer (4, const0_rtx);
+
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
   assemble_aligned_integer (POINTER_BYTES, const0_rtx);
 }
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 3ca6d61e7e28b780f94bf5080b126dac60fe0524..30693ce83fea1ccc6ee5e4aad1f0f0cd9b44f47a 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -240,6 +240,7 @@ 
     UNSPECV_BLOCKAGE		; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE	; Represent stack range probing.
     UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
+    UNSPECV_BTI_NOP		; Represent a BTI instruction.
   ]
 )
 
@@ -6720,6 +6721,40 @@ 
   [(set_attr "type" "csel")]
 )
 
+(define_insn "bti_nop"
+  [(unspec_volatile [(match_operand:SI 0 "const_int_operand")]
+    UNSPECV_BTI_NOP)]
+  ""
+  {
+   char buf[100];
+   bti_insn_type val = (bti_insn_type) INTVAL (operands[0]);
+   switch (val)
+    {
+      case INSN_BTI_NOARG:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti");
+	break;
+
+      case INSN_BTI_C:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti c");
+	break;
+
+      case INSN_BTI_J:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti j");
+	break;
+
+      case INSN_BTI_JC:
+	snprintf (buf, sizeof (buf), "hint\t%d // %s", val, "bti jc");
+	break;
+
+      default:
+	gcc_unreachable ();
+    }
+    output_asm_insn (buf, operands);
+    return "";
+   }
+  [(set_attr "type" "no_insn")]
+)
+
 ;; Helper for aarch64.c code.
 (define_expand "set_clobber_cc"
   [(parallel [(set (match_operand 0)
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index e91dccea9954c2c387fb111d1b357dd2c220ff0a..a2048547be56eba8a47c22c9d2b94e787364828f 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -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))
diff --git a/gcc/testsuite/gcc.target/aarch64/bti-1.c b/gcc/testsuite/gcc.target/aarch64/bti-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..575d01a5411a19dabcdb56b777e5d87d9703a848
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-1.c
@@ -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
index 0000000000000000000000000000000000000000..e50eef15c8936d00716c582e90b235add5da9136
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bti-2.c
@@ -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/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index fd74c04d092b0e2341b85eefbebb1f0df9423492..65ff16817f5f88255148bb69d7018975465197dc 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4270,6 +4270,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.