[12/15] arm: implement bti injection
Commit Message
Hi all,
this patch enables Branch Target Identification Armv8.1-M Mechanism
[1].
This is achieved by using the bti pass made common with Aarch64.
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.
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>
gcc/ChangeLog
2022-04-07 Andrea Corallo <andrea.corallo@arm.com>
* config.gcc (arm*-*-*): Add 'aarch-bti-insert.o' object.
* config/arm/arm-protos.h: Update.
* config/arm/arm.cc (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.md (bti_nop): New insn.
* config/arm/t-arm (PASSES_EXTRA): Add 'arm-passes.def'.
(aarch-bti-insert.o): New target.
* config/arm/unspecs.md (UNSPEC_BTI_NOP): New unspec.
* config/arm/aarch-bti-insert.cc (rest_of_insert_bti): Update
to verify arch compatibility.
* config/arm/arm-passes.def: New file.
gcc/testsuite/ChangeLog
2022-04-07 Andrea Corallo <andrea.corallo@arm.com>
* gcc.target/arm/bti-1.c: New testcase.
* gcc.target/arm/bti-2.c: Likewise.
Comments
Andrea Corallo via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> Hi all,
>
> this patch enables Branch Target Identification Armv8.1-M Mechanism
> [1].
>
> This is achieved by using the bti pass made common with Aarch64.
>
> 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.
>
> 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>
>
> gcc/ChangeLog
>
> 2022-04-07 Andrea Corallo <andrea.corallo@arm.com>
>
> * config.gcc (arm*-*-*): Add 'aarch-bti-insert.o' object.
> * config/arm/arm-protos.h: Update.
> * config/arm/arm.cc (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.md (bti_nop): New insn.
> * config/arm/t-arm (PASSES_EXTRA): Add 'arm-passes.def'.
> (aarch-bti-insert.o): New target.
> * config/arm/unspecs.md (UNSPEC_BTI_NOP): New unspec.
> * config/arm/aarch-bti-insert.cc (rest_of_insert_bti): Update
> to verify arch compatibility.
> * config/arm/arm-passes.def: New file.
>
> gcc/testsuite/ChangeLog
>
> 2022-04-07 Andrea Corallo <andrea.corallo@arm.com>
>
> * gcc.target/arm/bti-1.c: New testcase.
> * gcc.target/arm/bti-2.c: Likewise.
Ping
Andrea
Hi Andrea,
> -----Original Message-----
> From: Gcc-patches <gcc-patches-
> bounces+kyrylo.tkachov=arm.com@gcc.gnu.org> On Behalf Of Andrea
> Corallo via Gcc-patches
> Sent: Friday, August 12, 2022 4:42 PM
> To: Andrea Corallo via Gcc-patches <gcc-patches@gcc.gnu.org>
> Cc: Richard Earnshaw <Richard.Earnshaw@arm.com>; nd <nd@arm.com>
> Subject: [PATCH 12/15] arm: implement bti injection
>
> Hi all,
>
> this patch enables Branch Target Identification Armv8.1-M Mechanism
> [1].
>
> This is achieved by using the bti pass made common with Aarch64.
>
> 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.
>
> 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>
>
> gcc/ChangeLog
>
> 2022-04-07 Andrea Corallo <andrea.corallo@arm.com>
>
> * config.gcc (arm*-*-*): Add 'aarch-bti-insert.o' object.
> * config/arm/arm-protos.h: Update.
> * config/arm/arm.cc (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.md (bti_nop): New insn.
> * config/arm/t-arm (PASSES_EXTRA): Add 'arm-passes.def'.
> (aarch-bti-insert.o): New target.
> * config/arm/unspecs.md (UNSPEC_BTI_NOP): New unspec.
> * config/arm/aarch-bti-insert.cc (rest_of_insert_bti): Update
> to verify arch compatibility.
> * config/arm/arm-passes.def: New file.
>
> gcc/testsuite/ChangeLog
>
> 2022-04-07 Andrea Corallo <andrea.corallo@arm.com>
>
> * gcc.target/arm/bti-1.c: New testcase.
> * gcc.target/arm/bti-2.c: Likewise.
diff --git a/gcc/config/arm/aarch-bti-insert.cc b/gcc/config/arm/aarch-bti-insert.cc
index 2d1d2e334a9..8f045c247bf 100644
--- a/gcc/config/arm/aarch-bti-insert.cc
+++ b/gcc/config/arm/aarch-bti-insert.cc
@@ -41,6 +41,7 @@
#include "cfgrtl.h"
#include "tree-pass.h"
#include "cgraph.h"
+#include "diagnostic-core.h"
This change doesn't seem to match what's in the ChangeLog and doesn't make sense to me.
@@ -32985,6 +32979,58 @@ arm_current_function_pac_enabled_p (void)
&& !crtl->is_leaf);
}
+/* Return TRUE if Branch Target Identification Mechanism is enabled. */
+bool
+aarch_bti_enabled (void)
+{
+ return aarch_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) == UNSPEC_BTI_NOP;
+}
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction. */
The arm instructions are not PACIASP/PACIBSP.
This comment should be rewritten.
+bool
+aarch_pac_insn_p (rtx x)
+{
..........
+rtx
+aarch_gen_bti_c (void)
+{
+ return gen_bti_nop ();
+}
+
+rtx
+aarch_gen_bti_j (void)
+{
+ return gen_bti_nop ();
+}
+
A reader may be confused for why we have a bti_c and bti_j function that have identical functionality.
Please add function comments explaining the situation.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 92269a7819a..90c8c1d66f5 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -12913,6 +12913,13 @@
"aut\t%|ip, %|lr, %|sp"
[(set_attr "length" "4")])
+(define_insn "bti_nop"
+ [(unspec_volatile [(const_int 0)] UNSPEC_BTI_NOP)]
+ "arm_arch7 && arm_arch_cmse"
That seems like a copy-paste mistake. CMSE has nothing to do with this functionality?
+ "bti"
+ [(set_attr "length" "4")
The length of instructions in the arm backend is 4 by default, this set_attr can be omitted
+ (set_attr "type" "mov_reg")])
+
Probably better to use the "nop" attribute here?
Thanks,
Kyrill
@@ -353,7 +353,7 @@ arc*-*-*)
;;
arm*-*-*)
cpu_type=arm
- extra_objs="arm-builtins.o arm-mve-builtins.o aarch-common.o"
+ extra_objs="arm-builtins.o arm-mve-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"
@@ -41,6 +41,7 @@
#include "cfgrtl.h"
#include "tree-pass.h"
#include "cgraph.h"
+#include "diagnostic-core.h"
/* This pass enables the support for Branch Target Identification Mechanism for
Arm/AArch64. This is a security feature introduced in ARMv8.5-A
new file mode 100644
@@ -0,0 +1,21 @@
+/* Arm-specific passes declarations.
+ Copyright (C) 2022 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);
@@ -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);
@@ -23368,12 +23368,6 @@ output_probe_stack_range (rtx reg1, rtx reg2)
return "";
}
-static bool
-aarch_bti_enabled ()
-{
- return false;
-}
-
/* Generate the prologue instructions for entry into an ARM or Thumb-2
function. */
void
@@ -32985,6 +32979,58 @@ arm_current_function_pac_enabled_p (void)
&& !crtl->is_leaf);
}
+/* Return TRUE if Branch Target Identification Mechanism is enabled. */
+bool
+aarch_bti_enabled (void)
+{
+ return aarch_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) == UNSPEC_BTI_NOP;
+}
+
+/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction. */
+bool
+aarch_pac_insn_p (rtx x)
+{
+ if (!x || !INSN_P (x))
+ return false;
+
+ rtx pat = PATTERN (x);
+
+ if (GET_CODE (pat) == SET)
+ {
+ rtx tmp = XEXP (pat, 1);
+ if (tmp
+ && GET_CODE (tmp) == UNSPEC
+ && (XINT (tmp, 1) == UNSPEC_PAC_NOP
+ || XINT (tmp, 1) == UNSPEC_PACBTI_NOP))
+ return true;
+ }
+
+ return false;
+}
+
+rtx
+aarch_gen_bti_c (void)
+{
+ return gen_bti_nop ();
+}
+
+rtx
+aarch_gen_bti_j (void)
+{
+ return gen_bti_nop ();
+}
+
/* 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. */
@@ -12913,6 +12913,13 @@
"aut\t%|ip, %|lr, %|sp"
[(set_attr "length" "4")])
+(define_insn "bti_nop"
+ [(unspec_volatile [(const_int 0)] UNSPEC_BTI_NOP)]
+ "arm_arch7 && arm_arch_cmse"
+ "bti"
+ [(set_attr "length" "4")
+ (set_attr "type" "mov_reg")])
+
;; Vector bits common to IWMMXT, Neon and MVE
(include "vec-common.md")
;; Load the Intel Wireless Multimedia Extension patterns
@@ -175,3 +175,13 @@ arm-d.o: $(srcdir)/config/arm/arm-d.cc
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.cc \
+ $(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.cc
@@ -162,6 +162,7 @@
UNSPEC_PAC_NOP ; Represents PAC signing LR
UNSPEC_PACBTI_NOP ; Represents PAC signing LR + valid landing pad
UNSPEC_AUT_NOP ; Represents PAC verifying LR
+ UNSPEC_BTI_NOP ; Represent BTI
])
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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 } } */