[1/2] arm: add arm bti pass

Message ID gkree9g38qz.fsf@arm.com
State Superseded
Headers
Series [1/2] arm: add arm bti pass |

Commit Message

Andrea Corallo Sept. 22, 2021, 3:55 p.m. UTC
  Hi all,

this patch is part of a series that enables Armv8.1-M in GCC and adds
Branch Target Identification Mechanism [1].

This patch moves and generalize the Aarch64 "bti" pass so it can be
used also by the Arm backend.

The pass iterates through the instructions and adds the necessary BTI
instructions at the beginning of every function and at every landing
pads targeted by indirect jumps.

Regressioned and bootstraped on arm-linux-gnu aarch64-linux-gnu.

Best Regards

  Andrea

[1] <https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/armv8-1-m-pointer-authentication-and-branch-target-identification-extension>
From 94ee67dbc78c5ea15dde7114d7bffc18a5843cb7 Mon Sep 17 00:00:00 2001
From: Andrea Corallo <andrea.corallo@arm.com>
Date: Wed, 28 Jul 2021 15:49:16 +0200
Subject: [PATCH 1/2] arm: add arm bti pass

gcc/ChangeLog

2021-09-15  Andrea Corallo  <andrea.corallo@arm.com>

	* config/arm/unspecs.md (UNSPECV_BTI): Add unspec.

	* config/arm/t-arm (aarch-bti-insert.o): Add rule.

	* config/arm/arm.md (bti): New pattern.

	* config/arm/arm.c (aarch_bti_enabled, aarch_bti_j_insn_p)
	(aarch_pac_insn_p, aarch_gen_bti_c, aarch_gen_bti_j): New
	functions.

	* config/arm/arm-protos.h (make_pass_insert_bti): Add proto.

	* config/arm/arm-passes.def: New file.

	* config/arm/aarch-common-protos.h (aarch_bti_enabled)
	(aarch_bti_j_insn_p, aarch_pac_insn_p, aarch_gen_bti_c)
	(aarch_gen_bti_j): Add protos.

	* config/arm/aarch-bti-insert.c: New file, rename from
	'gcc/config/aarch64/aarch64-bti-insert.c' and generalize.

	* config/aarch64/t-aarch64 (aarch-bti-insert.o): Rename from
	'aarch64-bti-insert.o' and account for new folder.

	* config/aarch64/aarch64.c (aarch_bti_enabled)
	(aarch_bti_j_insn_p, aarch_pac_insn_p, aarch_gen_bti_c)
	(aarch_gen_bti_j): New functions.
	(aarch64_output_mi_thunk)
	(aarch64_print_patchable_function_entry)
	(aarch64_file_end_indicate_exec_stack): Rename 'aarch64_bti_enabled'
	=> 'aarch_bti_enabled'.

	* config/aarch64/aarch64-protos.h: Remove 'aarch64_bti_enabled'.

	* config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins): Rename
	'aarch64_bti_enabled' into 'aarch_bti_enabled'.

	* config.gcc (aarch64*-*-*): Rename 'aarch64-bti-insert.o' into
	'aarch-bti-insert.o'.
	(arm*-*-*): Add 'aarch-bti-insert.o'.

gcc/testsuite/ChangeLog

2021-09-15  Andrea Corallo  <andrea.corallo@arm.com>

	* gcc.target/arm/bti1.c: New testcase.

	* gcc.target/arm/bti2.c: Likewise.
---
 gcc/config.gcc                                |  4 +-
 gcc/config/aarch64/aarch64-c.c                |  2 +-
 gcc/config/aarch64/aarch64-protos.h           |  1 -
 gcc/config/aarch64/aarch64.c                  | 58 ++++++++++++++--
 gcc/config/aarch64/t-aarch64                  |  4 +-
 .../aarch-bti-insert.c}                       | 66 ++++---------------
 gcc/config/arm/aarch-common-protos.h          |  5 ++
 gcc/config/arm/arm-passes.def                 | 21 ++++++
 gcc/config/arm/arm-protos.h                   |  2 +
 gcc/config/arm/arm.c                          | 35 ++++++++++
 gcc/config/arm/arm.md                         |  6 ++
 gcc/config/arm/t-arm                          | 10 +++
 gcc/config/arm/unspecs.md                     |  1 +
 gcc/testsuite/gcc.target/arm/bti1.c           | 12 ++++
 gcc/testsuite/gcc.target/arm/bti2.c           | 58 ++++++++++++++++
 15 files changed, 222 insertions(+), 63 deletions(-)
 rename gcc/config/{aarch64/aarch64-bti-insert.c => arm/aarch-bti-insert.c} (80%)
 create mode 100644 gcc/config/arm/arm-passes.def
 create mode 100644 gcc/testsuite/gcc.target/arm/bti1.c
 create mode 100644 gcc/testsuite/gcc.target/arm/bti2.c
  

Comments

Andrea Corallo Oct. 18, 2021, 8:16 a.m. UTC | #1
Andrea Corallo via Gcc-patches <gcc-patches@gcc.gnu.org> writes:

> Hi all,
>
> this patch is part of a series that enables Armv8.1-M in GCC and adds
> Branch Target Identification Mechanism [1].
>
> This patch moves and generalize the Aarch64 "bti" pass so it can be
> used also by the Arm backend.
>
> The pass iterates through the instructions and adds the necessary BTI
> instructions at the beginning of every function and at every landing
> pads targeted by indirect jumps.
>
> Regressioned and bootstraped on arm-linux-gnu aarch64-linux-gnu.
>
> Best Regards
>
>   Andrea
>
> [1] <https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/armv8-1-m-pointer-authentication-and-branch-target-identification-extension>

Ping

Best Regards

  Andrea
  

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index d9bfbfdc0d2..648cf28e105 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -322,7 +322,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 aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o aarch64-cc-fusion.o"
+	extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch-bti-insert.o aarch64-cc-fusion.o"
 	target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc"
 	target_has_targetm_common=yes
 	;;
@@ -346,7 +346,7 @@  arc*-*-*)
 	;;
 arm*-*-*)
 	cpu_type=arm
-	extra_objs="arm-builtins.o aarch-common.o"
+	extra_objs="arm-builtins.o aarch-common.o aarch-bti-insert.o"
 	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h arm_cmse.h arm_bf16.h arm_mve_types.h arm_mve.h arm_cde.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index f9ddffa0078..5b8c03e094b 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -179,7 +179,7 @@  aarch64_update_cpp_builtins (cpp_reader *pfile)
   aarch64_def_or_undef (TARGET_RNG, "__ARM_FEATURE_RNG", pfile);
   aarch64_def_or_undef (TARGET_MEMTAG, "__ARM_FEATURE_MEMORY_TAGGING", pfile);
 
-  aarch64_def_or_undef (aarch64_bti_enabled (),
+  aarch64_def_or_undef (aarch_bti_enabled (),
 			"__ARM_FEATURE_BTI_DEFAULT", pfile);
 
   cpp_undef (pfile, "__ARM_FEATURE_PAC_DEFAULT");
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index b91eeeba101..fa87a4c7bb3 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -893,7 +893,6 @@  void aarch64_register_pragmas (void);
 void aarch64_relayout_simd_types (void);
 void aarch64_reset_previous_fndecl (void);
 bool aarch64_return_address_signing_enabled (void);
-bool aarch64_bti_enabled (void);
 void aarch64_save_restore_target_globals (tree);
 void aarch64_addti_scratch_regs (rtx, rtx, rtx *,
 				 rtx *, rtx *,
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 3213585a588..70edd179a61 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -7800,11 +7800,61 @@  aarch64_return_address_signing_enabled (void)
 
 /* Return TRUE if Branch Target Identification Mechanism is enabled.  */
 bool
-aarch64_bti_enabled (void)
+aarch_bti_enabled (void)
 {
   return (aarch64_enable_bti == 1);
 }
 
+/* Check if INSN is a BTI J insn.  */
+bool
+aarch_bti_j_insn_p (rtx_insn *insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  rtx pat = PATTERN (insn);
+  return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI_J;
+}
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction.  */
+bool
+aarch_pac_insn_p (rtx x)
+{
+  if (!INSN_P (x))
+    return false;
+
+  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;
+}
+
+rtx aarch_gen_bti_c (void)
+{
+  return gen_bti_c ();
+}
+
+rtx aarch_gen_bti_j (void)
+{
+  return gen_bti_j ();
+}
+
 /* The caller is going to use ST1D or LD1D to save or restore an SVE
    register in mode MODE at BASE_RTX + OFFSET, where OFFSET is in
    the range [1, 16] * GET_MODE_SIZE (MODE).  Prepare for this by:
@@ -9167,7 +9217,7 @@  aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
   rtx_insn *insn;
   const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk));
 
-  if (aarch64_bti_enabled ())
+  if (aarch_bti_enabled ())
     emit_insn (gen_bti_c());
 
   reload_completed = 1;
@@ -21407,7 +21457,7 @@  aarch64_print_patchable_function_entry (FILE *file,
 					bool record_p)
 {
   if (cfun->machine->label_is_assembled
-      && aarch64_bti_enabled ()
+      && aarch_bti_enabled ()
       && !cgraph_node::get (cfun->decl)->only_called_directly_p ())
     {
       /* Remove the BTI that follows the patch area and insert a new BTI
@@ -25531,7 +25581,7 @@  aarch64_file_end_indicate_exec_stack ()
   file_end_indicate_exec_stack ();
 
   unsigned feature_1_and = 0;
-  if (aarch64_bti_enabled ())
+  if (aarch_bti_enabled ())
     feature_1_and |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
 
   if (aarch64_ra_sign_scope != AARCH64_FUNCTION_NONE)
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index 7e1606c47ac..f6ace450e17 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -149,14 +149,14 @@  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 \
+aarch-bti-insert.o: $(srcdir)/config/arm/aarch-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
+		$(srcdir)/config/arm/aarch-bti-insert.c
 
 aarch64-cc-fusion.o: $(srcdir)/config/aarch64/aarch64-cc-fusion.cc \
     $(CONFIG_H) $(SYSTEM_H) $(CORETYPES_H) $(BACKEND_H) $(RTL_H) $(DF_H) \
diff --git a/gcc/config/aarch64/aarch64-bti-insert.c b/gcc/config/arm/aarch-bti-insert.c
similarity index 80%
rename from gcc/config/aarch64/aarch64-bti-insert.c
rename to gcc/config/arm/aarch-bti-insert.c
index 5d6bc169d6b..6b03238470b 100644
--- a/gcc/config/aarch64/aarch64-bti-insert.c
+++ b/gcc/config/arm/aarch-bti-insert.c
@@ -1,4 +1,4 @@ 
-/* Branch Target Identification for AArch64 architecture.
+/* Branch Target Identification for Arm/AArch64 architecture.
    Copyright (C) 2019-2021 Free Software Foundation, Inc.
    Contributed by Arm Ltd.
 
@@ -42,10 +42,11 @@ 
 #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.
+/* This pass enables the support for Branch Target Identification Mechanism for
+   Arm/AArch64.  This is a security feature introduced in ARMv8.5-A
+   architecture and ARMv8.1-M.  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
@@ -90,47 +91,6 @@  const pass_data pass_data_insert_bti =
   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 false;
-
-  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:
-            /* fall-through.  */
-            case UNSPEC_PACIBSP:
-	      return true;
-
-	    default:
-	      return false;
-	    }
-	  iter.skip_subrtxes ();
-	}
-    }
-  return false;
-}
-
-/* Check if INSN is a BTI J insn.  */
-static bool
-aarch64_bti_j_insn_p (rtx_insn *insn)
-{
-  if (!insn || !INSN_P (insn))
-    return false;
-
-  rtx pat = PATTERN (insn);
-  return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI_J;
-}
-
 /* Insert the BTI instruction.  */
 /* This is implemented as a late RTL pass that runs before branch
    shortening and does the following.  */
@@ -155,7 +115,7 @@  rest_of_insert_bti (void)
 	       && (LABEL_PRESERVE_P (insn)
 		   || bb->flags & BB_NON_LOCAL_GOTO_TARGET))
 	    {
-	      bti_insn = gen_bti_j ();
+	      bti_insn = aarch_gen_bti_j ();
 	      emit_insn_after (bti_insn, insn);
 	      continue;
 	    }
@@ -177,10 +137,10 @@  rest_of_insert_bti (void)
 		    {
 		      label = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, j), 0));
 		      rtx_insn *next = next_nonnote_nondebug_insn (label);
-		      if (aarch64_bti_j_insn_p (next))
+		      if (aarch_bti_j_insn_p (next))
 			continue;
 
-		      bti_insn = gen_bti_j ();
+		      bti_insn = aarch_gen_bti_j ();
 		      emit_insn_after (bti_insn, label);
 		    }
 		}
@@ -191,7 +151,7 @@  rest_of_insert_bti (void)
 	     will return.  */
 	  if (CALL_P (insn) && (find_reg_note (insn, REG_SETJMP, NULL)))
 	    {
-	      bti_insn = gen_bti_j ();
+	      bti_insn = aarch_gen_bti_j ();
 	      emit_insn_after (bti_insn, insn);
 	      continue;
 	    }
@@ -207,9 +167,9 @@  rest_of_insert_bti (void)
     {
       bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
       insn = BB_HEAD (bb);
-      if (!aarch64_pac_insn_p (get_first_nonnote_insn ()))
+      if (!aarch_pac_insn_p (get_first_nonnote_insn ()))
 	{
-	  bti_insn = gen_bti_c ();
+	  bti_insn = aarch_gen_bti_c ();
 	  emit_insn_before (bti_insn, insn);
 	}
     }
@@ -229,7 +189,7 @@  public:
   /* opt_pass methods: */
   virtual bool gate (function *)
     {
-      return aarch64_bti_enabled ();
+      return aarch_bti_enabled ();
     }
 
   virtual unsigned int execute (function *)
diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h
index 6be5fb1e083..1afebaabb9e 100644
--- a/gcc/config/arm/aarch-common-protos.h
+++ b/gcc/config/arm/aarch-common-protos.h
@@ -42,6 +42,11 @@  extern int arm_no_early_alu_shift_value_dep (rtx, rtx);
 extern int arm_no_early_mul_dep (rtx, rtx);
 extern int arm_no_early_store_addr_dep (rtx, rtx);
 extern bool arm_rtx_shift_left_p (rtx);
+extern bool aarch_bti_enabled (void);
+extern bool aarch_bti_j_insn_p (rtx_insn *);
+extern bool aarch_pac_insn_p (rtx);
+extern rtx aarch_gen_bti_c (void);
+extern rtx aarch_gen_bti_j (void);
 
 /* RTX cost table definitions.  These are used when tuning for speed rather
    than for size and should reflect the _additional_ cost over the cost
diff --git a/gcc/config/arm/arm-passes.def b/gcc/config/arm/arm-passes.def
new file mode 100644
index 00000000000..beecd2b5455
--- /dev/null
+++ b/gcc/config/arm/arm-passes.def
@@ -0,0 +1,21 @@ 
+/* Arm-specific passes declarations.
+   Copyright (C) 2021 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/>.  */
+
+INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_bti);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 9b1f61394ad..76064bafdca 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -24,6 +24,8 @@ 
 
 #include "sbitmap.h"
 
+rtl_opt_pass *make_pass_insert_bti (gcc::context *ctxt);
+
 extern enum unwind_info_type arm_except_unwind_info (struct gcc_options *);
 extern int use_return_insn (int, rtx);
 extern bool use_simple_return_p (void);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 11dafc70067..b62db21a734 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -32798,6 +32798,41 @@  arm_fusion_enabled_p (tune_params::fuse_ops op)
   return current_tune->fusible_ops & op;
 }
 
+/* Return TRUE if Branch Target Identification Mechanism is enabled.  */
+bool
+aarch_bti_enabled (void)
+{
+  return false; // FIXME
+}
+
+/* Check if INSN is a BTI J insn.  */
+bool
+aarch_bti_j_insn_p (rtx_insn *insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  rtx pat = PATTERN (insn);
+  return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI;
+}
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction.  */
+bool
+aarch_pac_insn_p (rtx x)
+{
+  return false;
+}
+
+rtx aarch_gen_bti_c (void)
+{
+  return gen_bti ();
+}
+
+rtx aarch_gen_bti_j (void)
+{
+  return gen_bti ();
+}
+
 /* Implement TARGET_SCHED_CAN_SPECULATE_INSN.  Return true if INSN can be
    scheduled for speculative execution.  Reject the long-running division
    and square-root instructions.  */
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 064604808cc..5fc8e76fb35 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -12800,6 +12800,12 @@ 
    (set_attr "length" "8")]
 )
 
+(define_insn "bti"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI)]
+  ""
+  "bti"
+  [(set_attr "type" "mov_reg")])
+
 ;; Vector bits common to IWMMXT, Neon and MVE
 (include "vec-common.md")
 ;; Load the Intel Wireless Multimedia Extension patterns
diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm
index 5f69ee6451e..358f7e5a707 100644
--- a/gcc/config/arm/t-arm
+++ b/gcc/config/arm/t-arm
@@ -165,3 +165,13 @@  arm-d.o: $(srcdir)/config/arm/arm-d.c
 arm-common.o: arm-cpu-cdata.h
 
 driver-arm.o: arm-native.h
+
+PASSES_EXTRA += $(srcdir)/config/arm/arm-passes.def
+
+aarch-bti-insert.o: $(srcdir)/config/arm/aarch-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
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+		$(srcdir)/config/arm/aarch-bti-insert.c
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index ad1c6edd005..be89f0a171c 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -159,6 +159,7 @@ 
   UNSPEC_VCDE		; Custom Datapath Extension instruction.
   UNSPEC_VCDEA		; Custom Datapath Extension instruction.
   UNSPEC_DLS		; Used for DLS (Do Loop Start), Armv8.1-M Mainline instruction
+  UNSPECV_BTI		; Represent BTI
 ])
 
 
diff --git a/gcc/testsuite/gcc.target/arm/bti1.c b/gcc/testsuite/gcc.target/arm/bti1.c
new file mode 100644
index 00000000000..230ebb5a1da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/bti1.c
@@ -0,0 +1,12 @@ 
+/* Check that GCC does bti instruction.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mthumb -mbranch-protection=bti --save-temps" } */
+
+int
+main (void)
+{
+  return 0;
+}
+
+/* { dg-final { scan-assembler "bti" } } */
diff --git a/gcc/testsuite/gcc.target/arm/bti2.c b/gcc/testsuite/gcc.target/arm/bti2.c
new file mode 100644
index 00000000000..35aef6992e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/bti2.c
@@ -0,0 +1,58 @@ 
+/* { dg-do compile } */
+/* -Os to create jump table.  */
+/* { dg-options "-Os" } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mthumb -mbranch-protection=bti --save-temps" } */
+
+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;
+}
+
+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 "bti" 15 } } */