1
0
mirror of https://git.yoctoproject.org/meta-arm synced 2026-07-26 19:17:05 +00:00
Files
Ross Burton b1dd7d90f6 Add GCS prototype
Signed-off-by: Ross Burton <ross.burton@arm.com>
2024-08-06 13:36:29 +01:00

1873 lines
56 KiB
Diff

Upstream-Status: Pending [vendors/ARM/gcs in gcc git]
Signed-off-by: Ross Burton <ross.burton@arm.com>
From e66be9a852ed255469f34dcd5ecf4c30e8721b66 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Mon, 19 Jun 2023 12:57:56 +0100
Subject: [PATCH 01/19] aarch64: Add -mbranch-protection=gcs option
This enables Guarded Control Stack (GCS) compatible code generation.
The "standard" branch-protection type enables it, and the default
depends on the compiler default.
TODO: gcs compatibility marking is missing.
gcc/ChangeLog:
* config/aarch64/aarch64-protos.h (aarch_gcs_enabled): Declare.
* config/aarch64/aarch64.cc (aarch_gcs_enabled): Define.
(aarch_handle_no_branch_protection): Handle gcs.
(aarch_handle_standard_branch_protection): Handle gcs.
(aarch_handle_gcs_protection): New.
* config/aarch64/aarch64.opt: Add aarch_enable_gcs.
* configure: Regenerate.
* configure.ac: Handle gcs in --enable-standard-branch-protection.
* doc/invoke.texi: Document -mbranch-protection=gcs.
---
gcc/config/aarch64/aarch64-protos.h | 2 ++
gcc/config/aarch64/aarch64.cc | 24 ++++++++++++++++++++++++
gcc/config/aarch64/aarch64.opt | 3 +++
gcc/configure | 2 +-
gcc/configure.ac | 2 +-
gcc/doc/invoke.texi | 5 +++--
6 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index bd719b992a5..2802bc935c9 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -1113,4 +1113,6 @@ extern void aarch64_adjust_reg_alloc_order ();
bool aarch64_optimize_mode_switching (aarch64_mode_entity);
void aarch64_restore_za (rtx);
+extern bool aarch64_gcs_enabled ();
+
#endif /* GCC_AARCH64_PROTOS_H */
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 1ea84c8bd73..73969721906 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -8375,6 +8375,13 @@ aarch_bti_j_insn_p (rtx_insn *insn)
return GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_BTI_J;
}
+/* Return TRUE if Guarded Control Stack is enabled. */
+bool
+aarch64_gcs_enabled (void)
+{
+ return (aarch64_enable_gcs == 1);
+}
+
/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction. */
bool
aarch_pac_insn_p (rtx x)
@@ -18694,6 +18701,7 @@ aarch64_handle_no_branch_protection (void)
{
aarch_ra_sign_scope = AARCH_FUNCTION_NONE;
aarch_enable_bti = 0;
+ aarch64_enable_gcs = 0;
}
static void
@@ -18702,6 +18710,7 @@ aarch64_handle_standard_branch_protection (void)
aarch_ra_sign_scope = AARCH_FUNCTION_NON_LEAF;
aarch64_ra_sign_key = AARCH64_KEY_A;
aarch_enable_bti = 1;
+ aarch64_enable_gcs = 1;
}
static void
@@ -18728,6 +18737,11 @@ aarch64_handle_bti_protection (void)
{
aarch_enable_bti = 1;
}
+static void
+aarch64_handle_gcs_protection (void)
+{
+ aarch64_enable_gcs = 1;
+}
static const struct aarch_branch_protect_type aarch64_pac_ret_subtypes[] = {
{ "leaf", false, aarch64_handle_pac_ret_leaf, NULL, 0 },
@@ -18742,6 +18756,7 @@ static const struct aarch_branch_protect_type aarch64_branch_protect_types[] =
{ "pac-ret", false, aarch64_handle_pac_ret_protection,
aarch64_pac_ret_subtypes, ARRAY_SIZE (aarch64_pac_ret_subtypes) },
{ "bti", false, aarch64_handle_bti_protection, NULL, 0 },
+ { "gcs", false, aarch64_handle_gcs_protection, NULL, 0 },
{ NULL, false, NULL, NULL, 0 }
};
@@ -18842,6 +18857,15 @@ aarch64_override_options (void)
#endif
}
+ if (aarch64_enable_gcs == 2)
+ {
+#ifdef TARGET_ENABLE_GCS
+ aarch64_enable_gcs = 1;
+#else
+ aarch64_enable_gcs = 0;
+#endif
+ }
+
/* Return address signing is currently not supported for ILP32 targets. For
LP64 targets use the configured option in the absence of a command-line
option for -mbranch-protection. */
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 6356c419399..aeb710449fb 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -39,6 +39,9 @@ aarch64_feature_flags aarch64_isa_flags = 0
TargetVariable
unsigned aarch_enable_bti = 2
+TargetVariable
+unsigned aarch64_enable_gcs = 2
+
TargetVariable
enum aarch64_key_type aarch64_ra_sign_key = AARCH64_KEY_A
diff --git a/gcc/configure b/gcc/configure
index 266ab8f84b2..45725639fd2 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -28221,7 +28221,7 @@ if test "${enable_standard_branch_protection+set}" = set; then :
enableval=$enable_standard_branch_protection;
case $enableval in
yes)
- tm_defines="${tm_defines} TARGET_ENABLE_BTI=1 TARGET_ENABLE_PAC_RET=1"
+ tm_defines="${tm_defines} TARGET_ENABLE_BTI=1 TARGET_ENABLE_PAC_RET=1 TARGET_ENABLE_GCS=1"
;;
no)
;;
diff --git a/gcc/configure.ac b/gcc/configure.ac
index a5aec1bc967..30d59ce7949 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4440,7 +4440,7 @@ AS_HELP_STRING([--disable-standard-branch-protection],
[
case $enableval in
yes)
- tm_defines="${tm_defines} TARGET_ENABLE_BTI=1 TARGET_ENABLE_PAC_RET=1"
+ tm_defines="${tm_defines} TARGET_ENABLE_BTI=1 TARGET_ENABLE_PAC_RET=1 TARGET_ENABLE_GCS=1"
;;
no)
;;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1006510fc6a..b5e2697193f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -801,7 +801,7 @@ Objective-C and Objective-C++ Dialects}.
-mpc-relative-literal-loads
-msign-return-address=@var{scope}
-mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}
-+@var{b-key}]|@var{bti}
++@var{b-key}]|@var{bti}|@var{gcs}
-mharden-sls=@var{opts}
-march=@var{name} -mcpu=@var{name} -mtune=@var{name}
-moverride=@var{string} -mverbose-cost-dump
@@ -21408,7 +21408,7 @@ default value is @samp{none}. This option has been deprecated by
-mbranch-protection.
@opindex mbranch-protection
-@item -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}+@var{b-key}]|@var{bti}
+@item -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}+@var{b-key}]|@var{bti}|@var{gcs}
Select the branch protection features to use.
@samp{none} is the default and turns off all types of branch protection.
@samp{standard} turns on all types of branch protection features. If a feature
@@ -21421,6 +21421,7 @@ argument @samp{leaf} can be used to extend the signing to include leaf
functions. The optional argument @samp{b-key} can be used to sign the functions
with the B-key instead of the A-key.
@samp{bti} turns on branch target identification mechanism.
+@samp{gcs} turns on guarded control stack compatible code generation.
@opindex mharden-sls
@item -mharden-sls=@var{opts}
--
2.34.1
From c947c0551c793aeff90139718eb7d731d543ee08 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Fri, 30 Jun 2023 16:31:23 +0100
Subject: [PATCH 02/19] aarch64: Add branch-protection target pragma tests
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/pragma_cpp_predefs_4.c: Add branch-protection
tests.
---
.../gcc.target/aarch64/pragma_cpp_predefs_4.c | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
index 23ebe5e4f50..8e707630774 100644
--- a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
+++ b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
@@ -83,3 +83,53 @@
#ifndef __ARM_FEATURE_SME_F64F64
#error Foo
#endif
+
+#pragma GCC target "branch-protection=standard"
+#ifndef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#if __ARM_FEATURE_PAC_DEFAULT != 1
+#error Foo
+#endif
+
+#pragma GCC target ("branch-protection=none")
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#error Foo
+#endif
+
+#pragma GCC push_options
+#pragma GCC target "branch-protection=bti+pac-ret"
+#ifndef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#pragma GCC pop_options
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+
+#pragma GCC target "branch-protection=bti"
+#ifndef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#error Foo
+#endif
+
+#pragma GCC target "branch-protection=pac-ret"
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#if __ARM_FEATURE_PAC_DEFAULT != 1
+#error Foo
+#endif
+
+#pragma GCC target "branch-protection=pac-ret+leaf+b-key"
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#if __ARM_FEATURE_PAC_DEFAULT != 6
+#error Foo
+#endif
--
2.34.1
From 99367f7410b3c328d67051734145f3970b84ee6f Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Fri, 30 Jun 2023 16:50:23 +0100
Subject: [PATCH 03/19] aarch64: Add target pragma tests for gcs
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/pragma_cpp_predefs_4.c: Add gcs specific
tests.
---
.../gcc.target/aarch64/pragma_cpp_predefs_4.c | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
index 8e707630774..417293d4d5a 100644
--- a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
+++ b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
@@ -91,6 +91,9 @@
#if __ARM_FEATURE_PAC_DEFAULT != 1
#error Foo
#endif
+#ifndef __ARM_FEATURE_GCS_DEFAULT
+#error Foo
+#endif
#pragma GCC target ("branch-protection=none")
#ifdef __ARM_FEATURE_BTI_DEFAULT
@@ -99,6 +102,9 @@
#ifdef __ARM_FEATURE_PAC_DEFAULT
#error Foo
#endif
+#ifdef __ARM_FEATURE_GCS_DEFAULT
+#error Foo
+#endif
#pragma GCC push_options
#pragma GCC target "branch-protection=bti+pac-ret"
@@ -117,6 +123,9 @@
#ifdef __ARM_FEATURE_PAC_DEFAULT
#error Foo
#endif
+#ifdef __ARM_FEATURE_GCS_DEFAULT
+#error Foo
+#endif
#pragma GCC target "branch-protection=pac-ret"
#ifdef __ARM_FEATURE_BTI_DEFAULT
@@ -133,3 +142,29 @@
#if __ARM_FEATURE_PAC_DEFAULT != 6
#error Foo
#endif
+
+#pragma GCC target "branch-protection=gcs"
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#error Foo
+#endif
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#error Foo
+#endif
+#ifndef __ARM_FEATURE_GCS_DEFAULT
+#error Foo
+#endif
+
+#pragma GCC target "arch=armv8.8-a+gcs"
+#ifndef __ARM_FEATURE_GCS
+#error Foo
+#endif
+
+#pragma GCC target "arch=armv8.8-a+nogcs"
+#ifdef __ARM_FEATURE_GCS
+#error Foo
+#endif
+
+#pragma GCC target "arch=armv8.8-a"
+#ifdef __ARM_FEATURE_GCS
+#error Foo
+#endif
--
2.34.1
From f2a000e3b40953985a778875d1a908822ca9ffbd Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 9 May 2023 15:37:49 +0100
Subject: [PATCH 04/19] aarch64: Add support for chkfeat insn
This is a hint space instruction to check for enabled HW features and
update the x16 register accordingly.
Use unspec_volatile to prevent reordering it around calls since calls
can enable or disable HW features.
gcc/ChangeLog:
* config/aarch64/aarch64.md (aarch64_chkfeat): New.
---
gcc/config/aarch64/aarch64.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 385a669b9b3..a20462303b5 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -378,6 +378,7 @@
UNSPECV_BTI_C ; Represent BTI c.
UNSPECV_BTI_J ; Represent BTI j.
UNSPECV_BTI_JC ; Represent BTI jc.
+ UNSPECV_CHKFEAT ; Represent CHKFEAT X16.
UNSPECV_TSTART ; Represent transaction start.
UNSPECV_TCOMMIT ; Represent transaction commit.
UNSPECV_TCANCEL ; Represent transaction cancel.
@@ -8258,6 +8259,14 @@
"msr\tnzcv, %0"
)
+;; CHKFEAT instruction
+(define_insn "aarch64_chkfeat"
+ [(set (reg:DI R16_REGNUM)
+ (unspec_volatile:DI [(reg:DI R16_REGNUM)] UNSPECV_CHKFEAT))]
+ ""
+ "hint\\t40 // chkfeat x16"
+)
+
;; AdvSIMD Stuff
(include "aarch64-simd.md")
--
2.34.1
From 6a5358558591549fb2fb5b210c9681b0d694d1af Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 9 May 2023 15:24:18 +0100
Subject: [PATCH 05/19] aarch64: Add __builtin_aarch64_chkfeat
Builtin for chkfeat: the input argument is used to initialize x16 then
execute chkfeat and return the updated x16.
Note: ACLE __chkfeat(x) plans to flip the bits to be more intuitive
(xor the input to output), but for the builtin that seems unnecessary
complication.
gcc/ChangeLog:
* config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
Define AARCH64_BUILTIN_CHKFEAT.
(aarch64_general_init_builtins): Handle chkfeat.
(aarch64_general_expand_builtin): Handle chkfeat.
---
gcc/config/aarch64/aarch64-builtins.cc | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index 75d21de1401..1c08f56ab6b 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -788,6 +788,8 @@ enum aarch64_builtins
AARCH64_PLDX,
AARCH64_PLI,
AARCH64_PLIX,
+ /* Armv8.9-A / Armv9.4-A builtins. */
+ AARCH64_BUILTIN_CHKFEAT,
AARCH64_BUILTIN_MAX
};
@@ -2084,6 +2086,12 @@ aarch64_general_init_builtins (void)
if (TARGET_MEMTAG)
aarch64_init_memtag_builtins ();
+ tree ftype_chkfeat
+ = build_function_type_list (uint64_type_node, uint64_type_node, NULL);
+ aarch64_builtin_decls[AARCH64_BUILTIN_CHKFEAT]
+ = aarch64_general_add_builtin ("__builtin_aarch64_chkfeat", ftype_chkfeat,
+ AARCH64_BUILTIN_CHKFEAT);
+
if (in_lto_p)
handle_arm_acle_h ();
}
@@ -3137,6 +3145,16 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
case AARCH64_PLIX:
aarch64_expand_prefetch_builtin (exp, fcode);
return target;
+
+ case AARCH64_BUILTIN_CHKFEAT:
+ {
+ rtx x16_reg = gen_rtx_REG (DImode, R16_REGNUM);
+ op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+ emit_move_insn (x16_reg, op0);
+ expand_insn (CODE_FOR_aarch64_chkfeat, 0, 0);
+ emit_move_insn (target, x16_reg);
+ return target;
+ }
}
if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
--
2.34.1
From fd2868c17ad14374147adc83d62ef24b60718509 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Fri, 2 Jun 2023 16:15:25 +0100
Subject: [PATCH 06/19] aarch64: Add __builtin_aarch64_chkfeat tests
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/chkfeat-1.c: New test.
* gcc.target/aarch64/chkfeat-2.c: New test.
---
gcc/testsuite/gcc.target/aarch64/chkfeat-1.c | 75 ++++++++++++++++++++
gcc/testsuite/gcc.target/aarch64/chkfeat-2.c | 15 ++++
2 files changed, 90 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/chkfeat-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/chkfeat-2.c
diff --git a/gcc/testsuite/gcc.target/aarch64/chkfeat-1.c b/gcc/testsuite/gcc.target/aarch64/chkfeat-1.c
new file mode 100644
index 00000000000..2fae81e740f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/chkfeat-1.c
@@ -0,0 +1,75 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbranch-protection=none" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+**foo1:
+** mov x16, 1
+** hint 40 // chkfeat x16
+** mov x0, x16
+** ret
+*/
+unsigned long long
+foo1 (void)
+{
+ return __builtin_aarch64_chkfeat (1);
+}
+
+/*
+**foo2:
+** mov x16, 1
+** movk x16, 0x5678, lsl 32
+** movk x16, 0x1234, lsl 48
+** hint 40 // chkfeat x16
+** mov x0, x16
+** ret
+*/
+unsigned long long
+foo2 (void)
+{
+ return __builtin_aarch64_chkfeat (0x1234567800000001);
+}
+
+/*
+**foo3:
+** mov x16, x0
+** hint 40 // chkfeat x16
+** mov x0, x16
+** ret
+*/
+unsigned long long
+foo3 (unsigned long long x)
+{
+ return __builtin_aarch64_chkfeat (x);
+}
+
+/*
+**foo4:
+** ldr x16, \[x0\]
+** hint 40 // chkfeat x16
+** str x16, \[x0\]
+** ret
+*/
+void
+foo4 (unsigned long long *p)
+{
+ *p = __builtin_aarch64_chkfeat (*p);
+}
+
+/*
+**foo5:
+** mov x16, 1
+** hint 40 // chkfeat x16
+** cmp x16, 0
+**(
+** csel w0, w1, w0, eq
+**|
+** csel w0, w0, w1, ne
+**)
+** ret
+*/
+int
+foo5 (int x, int y)
+{
+ return __builtin_aarch64_chkfeat (1) ? x : y;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/chkfeat-2.c b/gcc/testsuite/gcc.target/aarch64/chkfeat-2.c
new file mode 100644
index 00000000000..682524e244f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/chkfeat-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times {hint\t40 // chkfeat x16} 2 } } */
+
+void bar (void);
+
+/* Extern call may change enabled HW features. */
+unsigned long long
+foo (void)
+{
+ unsigned long long a = __builtin_aarch64_chkfeat (1);
+ bar ();
+ unsigned long long b = __builtin_aarch64_chkfeat (1);
+ return a + b;
+}
--
2.34.1
From 409aac824e3a69848a60daafcaeedc5f18c357dd Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 9 May 2023 16:00:01 +0100
Subject: [PATCH 07/19] aarch64: Add GCS instructions
Add instructions for the Guarded Control Stack extension.
GCSSS1 and GCSSS2 are modelled as a single GCSSS unspec, because they
are always used together in the compiler.
Before GCSPOPM and GCSSS2 an extra "mov xn, 0" is added to clear the
output register, this is needed to get reasonable result when GCS is
disabled, when the instructions are NOPs. Since the instructions are
expecetd to be used behind runtime feature checks, this is mainly
relevant if GCS can be disabled asynchronously.
The output of GCSPOPM is usually not needed, so a separate gcspopm_xzr
was added to model that. Did not do the same for GCSSS as it is a less
common operation.
The used mnemonics do not depend on updated assembler since these
instructions can be used without new -march setting behind a runtime
check.
Reading the GCSPR is modelled as unspec_volatile so it does not get
reordered wrt the other instructions changing the GCSPR.
TODO:
- Do we care about async disable?
- Do we need GCSSS_xzr? (to avoid the mov x,0)
gcc/ChangeLog:
* config/aarch64/aarch64.md (aarch64_load_gcspr): New.
(aarch64_gcspopm): New.
(aarch64_gcspopm_xzr): New.
(aarch64_gcsss): New.
---
gcc/config/aarch64/aarch64.md | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index a20462303b5..8defd6e0582 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -379,6 +379,9 @@
UNSPECV_BTI_J ; Represent BTI j.
UNSPECV_BTI_JC ; Represent BTI jc.
UNSPECV_CHKFEAT ; Represent CHKFEAT X16.
+ UNSPECV_GCSPR ; Represent MRS Xn, GCSPR_EL0
+ UNSPECV_GCSPOPM ; Represent GCSPOPM.
+ UNSPECV_GCSSS ; Represent GCSSS1 and GCSSS2.
UNSPECV_TSTART ; Represent transaction start.
UNSPECV_TCOMMIT ; Represent transaction commit.
UNSPECV_TCANCEL ; Represent transaction cancel.
@@ -8267,6 +8270,38 @@
"hint\\t40 // chkfeat x16"
)
+;; Guarded Control Stack (GCS) instructions
+(define_insn "aarch64_load_gcspr"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(const_int 0)] UNSPECV_GCSPR))]
+ ""
+ "mrs\\t%0, s3_3_c2_c5_1 // gcspr_el0"
+ [(set_attr "type" "mrs")]
+)
+
+(define_insn "aarch64_gcspopm"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(const_int 0)] UNSPECV_GCSPOPM))]
+ ""
+ "mov\\t%0, 0\;sysl\\t%0, #3, c7, c7, #1 // gcspopm"
+ [(set_attr "length" "8")]
+)
+
+(define_insn "aarch64_gcspopm_xzr"
+ [(unspec_volatile [(const_int 0)] UNSPECV_GCSPOPM)]
+ ""
+ "sysl\\txzr, #3, c7, c7, #1 // gcspopm"
+)
+
+(define_insn "aarch64_gcsss"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")]
+ UNSPECV_GCSSS))]
+ ""
+ "sys\\t#3, c7, c7, #2, %1 // gcsss1\;mov\\t%0, 0\;sysl\\t%0, #3, c7, c7, #3 // gcsss2"
+ [(set_attr "length" "12")]
+)
+
;; AdvSIMD Stuff
(include "aarch64-simd.md")
--
2.34.1
From 9e6a37fd99e22e3cd3d685100763c9ed201019ee Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 9 May 2023 16:21:28 +0100
Subject: [PATCH 08/19] aarch64: Add GCS builtins
Add new builtins for GCS:
void *__builtin_aarch64_gcspr (void)
uint64_t __builtin_aarch64_gcspopm (void)
void *__builtin_aarch64_gcsss (void *)
The builtins are always enabled, but should be used behind runtime
checks in case the target does not support GCS. They are thin
wrappers around the corresponding instructions.
The GCS pointer is modelled with void * type (normal stores do not
work on GCS memory, but it is writable via the gcsss operation or
via GCSSTR if enabled so not const) and an entry on the GCS is
modelled with uint64_t (since it has fixed size and can be a token
that's not a pointer).
gcc/ChangeLog:
* config/aarch64/aarch64-builtins.cc (enum aarch64_builtins): Add
AARCH64_BUILTIN_GCSPR, AARCH64_BUILTIN_GCSPOPM, AARCH64_BUILTIN_GCSSS.
(aarch64_init_gcs_builtins): New.
(aarch64_general_init_builtins): Call aarch64_init_gcs_builtins.
(aarch64_expand_gcs_builtin): New.
(aarch64_general_expand_builtin): Call aarch64_expand_gcs_builtin.
---
gcc/config/aarch64/aarch64-builtins.cc | 70 ++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index 1c08f56ab6b..30c977586f9 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -790,6 +790,9 @@ enum aarch64_builtins
AARCH64_PLIX,
/* Armv8.9-A / Armv9.4-A builtins. */
AARCH64_BUILTIN_CHKFEAT,
+ AARCH64_BUILTIN_GCSPR,
+ AARCH64_BUILTIN_GCSPOPM,
+ AARCH64_BUILTIN_GCSSS,
AARCH64_BUILTIN_MAX
};
@@ -2041,6 +2044,29 @@ aarch64_init_fpsr_fpcr_builtins (void)
AARCH64_BUILTIN_SET_FPSR64);
}
+/* Add builtins for Guarded Control Stack instructions. */
+
+static void
+aarch64_init_gcs_builtins (void)
+{
+ tree ftype;
+
+ ftype = build_function_type_list (ptr_type_node, NULL);
+ aarch64_builtin_decls[AARCH64_BUILTIN_GCSPR]
+ = aarch64_general_add_builtin ("__builtin_aarch64_gcspr", ftype,
+ AARCH64_BUILTIN_GCSPR);
+
+ ftype = build_function_type_list (uint64_type_node, NULL);
+ aarch64_builtin_decls[AARCH64_BUILTIN_GCSPOPM]
+ = aarch64_general_add_builtin ("__builtin_aarch64_gcspopm", ftype,
+ AARCH64_BUILTIN_GCSPOPM);
+
+ ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL);
+ aarch64_builtin_decls[AARCH64_BUILTIN_GCSSS]
+ = aarch64_general_add_builtin ("__builtin_aarch64_gcsss", ftype,
+ AARCH64_BUILTIN_GCSSS);
+}
+
/* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */
void
@@ -2092,6 +2118,8 @@ aarch64_general_init_builtins (void)
= aarch64_general_add_builtin ("__builtin_aarch64_chkfeat", ftype_chkfeat,
AARCH64_BUILTIN_CHKFEAT);
+ aarch64_init_gcs_builtins ();
+
if (in_lto_p)
handle_arm_acle_h ();
}
@@ -3020,6 +3048,43 @@ aarch64_expand_fpsr_fpcr_getter (enum insn_code icode, machine_mode mode,
return op.value;
}
+/* Expand GCS builtin EXP with code FCODE, putting the result
+ int TARGET. If IGNORE is true the return value is ignored. */
+
+rtx
+aarch64_expand_gcs_builtin (tree exp, rtx target, int fcode, int ignore)
+{
+ if (fcode == AARCH64_BUILTIN_GCSPR)
+ {
+ expand_operand op;
+ create_output_operand (&op, target, DImode);
+ expand_insn (CODE_FOR_aarch64_load_gcspr, 1, &op);
+ return op.value;
+ }
+ if (fcode == AARCH64_BUILTIN_GCSPOPM && ignore)
+ {
+ expand_insn (CODE_FOR_aarch64_gcspopm_xzr, 0, 0);
+ return target;
+ }
+ if (fcode == AARCH64_BUILTIN_GCSPOPM)
+ {
+ expand_operand op;
+ create_output_operand (&op, target, Pmode);
+ expand_insn (CODE_FOR_aarch64_gcspopm, 1, &op);
+ return op.value;
+ }
+ if (fcode == AARCH64_BUILTIN_GCSSS)
+ {
+ expand_operand ops[2];
+ rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 0));
+ create_output_operand (&ops[0], target, Pmode);
+ create_input_operand (&ops[1], op1, Pmode);
+ expand_insn (CODE_FOR_aarch64_gcsss, 2, ops);
+ return ops[0].value;
+ }
+ gcc_unreachable ();
+}
+
/* Expand an expression EXP that calls built-in function FCODE,
with result going to TARGET if that's convenient. IGNORE is true
if the result of the builtin is ignored. */
@@ -3155,6 +3220,11 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
emit_move_insn (target, x16_reg);
return target;
}
+
+ case AARCH64_BUILTIN_GCSPR:
+ case AARCH64_BUILTIN_GCSPOPM:
+ case AARCH64_BUILTIN_GCSSS:
+ return aarch64_expand_gcs_builtin (exp, target, fcode, ignore);
}
if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
--
2.34.1
From d4d950feefc4f55da32be812eb882a2f66aadcaf Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 6 Jun 2023 17:35:51 +0100
Subject: [PATCH 09/19] aarch64: Add __builtin_aarch64_gcs* tests
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/gcspopm-1.c: New test.
* gcc.target/aarch64/gcspr-1.c: New test.
* gcc.target/aarch64/gcsss-1.c: New test.
---
gcc/testsuite/gcc.target/aarch64/gcspopm-1.c | 69 ++++++++++++++++++++
gcc/testsuite/gcc.target/aarch64/gcspr-1.c | 31 +++++++++
gcc/testsuite/gcc.target/aarch64/gcsss-1.c | 49 ++++++++++++++
3 files changed, 149 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/gcspopm-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/gcspr-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/gcsss-1.c
diff --git a/gcc/testsuite/gcc.target/aarch64/gcspopm-1.c b/gcc/testsuite/gcc.target/aarch64/gcspopm-1.c
new file mode 100644
index 00000000000..6e6add39cf7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/gcspopm-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbranch-protection=none" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+**foo1:
+** sysl xzr, #3, c7, c7, #1 // gcspopm
+** ret
+*/
+void
+foo1 (void)
+{
+ __builtin_aarch64_gcspopm ();
+}
+
+/*
+**foo2:
+** mov x0, 0
+** sysl x0, #3, c7, c7, #1 // gcspopm
+** ret
+*/
+unsigned long long
+foo2 (void)
+{
+ return __builtin_aarch64_gcspopm ();
+}
+
+/*
+**foo3:
+** mov x16, 1
+** (
+** mov x0, 0
+** hint 40 // chkfeat x16
+** |
+** hint 40 // chkfeat x16
+** mov x0, 0
+** )
+** cbz x16, .*
+** ret
+** mov x0, 0
+** sysl x0, #3, c7, c7, #1 // gcspopm
+** ret
+*/
+unsigned long long
+foo3 (void)
+{
+ if (__builtin_aarch64_chkfeat (1) == 0)
+ return __builtin_aarch64_gcspopm ();
+ return 0;
+}
+
+/*
+**foo4:
+** sysl xzr, #3, c7, c7, #1 // gcspopm
+** mov x0, 0
+** sysl x0, #3, c7, c7, #1 // gcspopm
+** sysl xzr, #3, c7, c7, #1 // gcspopm
+** ret
+*/
+unsigned long long
+foo4 (void)
+{
+ unsigned long long a = __builtin_aarch64_gcspopm ();
+ unsigned long long b = __builtin_aarch64_gcspopm ();
+ unsigned long long c = __builtin_aarch64_gcspopm ();
+ (void) a;
+ (void) c;
+ return b;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/gcspr-1.c b/gcc/testsuite/gcc.target/aarch64/gcspr-1.c
new file mode 100644
index 00000000000..0e651979551
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/gcspr-1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbranch-protection=none" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+**foo1:
+** mrs x0, s3_3_c2_c5_1 // gcspr_el0
+** ret
+*/
+void *
+foo1 (void)
+{
+ return __builtin_aarch64_gcspr ();
+}
+
+/*
+**foo2:
+** mrs x[0-9]*, s3_3_c2_c5_1 // gcspr_el0
+** sysl xzr, #3, c7, c7, #1 // gcspopm
+** mrs x[0-9]*, s3_3_c2_c5_1 // gcspr_el0
+** sub x0, x[0-9]*, x[0-9]*
+** ret
+*/
+long
+foo2 (void)
+{
+ const char *p = __builtin_aarch64_gcspr ();
+ __builtin_aarch64_gcspopm ();
+ const char *q = __builtin_aarch64_gcspr ();
+ return p - q;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/gcsss-1.c b/gcc/testsuite/gcc.target/aarch64/gcsss-1.c
new file mode 100644
index 00000000000..025c7fee647
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/gcsss-1.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbranch-protection=none" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+**foo1:
+** sys #3, c7, c7, #2, x0 // gcsss1
+** mov x[0-9]*, 0
+** sysl x[0-9]*, #3, c7, c7, #3 // gcsss2
+** ret
+*/
+void
+foo1 (void *p)
+{
+ __builtin_aarch64_gcsss (p);
+}
+
+/*
+**foo2:
+** sys #3, c7, c7, #2, x0 // gcsss1
+** mov x0, 0
+** sysl x0, #3, c7, c7, #3 // gcsss2
+** ret
+*/
+void *
+foo2 (void *p)
+{
+ return __builtin_aarch64_gcsss (p);
+}
+
+/*
+**foo3:
+** mov x16, 1
+** hint 40 // chkfeat x16
+** cbnz x16, .*
+** sys #3, c7, c7, #2, x0 // gcsss1
+** mov x0, 0
+** sysl x0, #3, c7, c7, #3 // gcsss2
+** ret
+** mov x0, 0
+** ret
+*/
+void *
+foo3 (void *p)
+{
+ if (__builtin_aarch64_chkfeat (1) == 0)
+ return __builtin_aarch64_gcsss (p);
+ return 0;
+}
--
2.34.1
From 57b7b8934997cbd3eceb84b8de30b83f05760ecc Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Fri, 14 Apr 2023 18:23:52 +0100
Subject: [PATCH 10/19] aarch64: Add GCS support for nonlocal stack save
Nonlocal stack save and restore has to also save and restore the GCS
pointer. This is used in __builtin_setjmp/longjmp and nonlocal goto.
The GCS specific code is only emitted if GCS branch-protection is
enabled and the code always checks at runtime if GCS is enabled.
The new -mbranch-protection=gcs and old -mbranch-protection=none code
are ABI compatible: jmpbuf for __builtin_setjmp has space for 5
pointers, the layout is
old layout: fp, pc, sp, unused, unused
new layout: fp, pc, sp, gcsp, unused
Note: the ILP32 code generation is wrong as it saves the pointers with
Pmode (i.e. 8 bytes per pointer), but the user supplied buffer size is
for 5 pointers (4 bytes per pointer), this is not fixed.
The nonlocal goto has no ABI compatibility issues as the goto and its
destination are in the same translation unit.
TODO:
- can we simplify the define_expand rtls?
gcc/ChangeLog:
* config/aarch64/aarch64.h (STACK_SAVEAREA_MODE): Make space for gcs.
* config/aarch64/aarch64.md (save_stack_nonlocal): New.
(restore_stack_nonlocal): New.
---
gcc/config/aarch64/aarch64.h | 7 +++
gcc/config/aarch64/aarch64.md | 82 +++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 45e901cda64..3238452f53f 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -1294,6 +1294,13 @@ typedef struct
#define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
((VALUE) = GET_MODE_UNIT_BITSIZE (MODE), 2)
+/* Have space for both SP and GCSPR in the NONLOCAL case in
+ emit_stack_save as well as in __builtin_setjmp, __builtin_longjmp
+ and __builtin_nonlocal_goto.
+ Note: On ILP32 the documented buf size is not enough PR84150. */
+#define STACK_SAVEAREA_MODE(LEVEL) \
+ ((LEVEL) == SAVE_NONLOCAL ? TImode : Pmode)
+
#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LR_REGNUM)
#define RETURN_ADDR_RTX aarch64_return_addr
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 8defd6e0582..2d36af12cfb 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -1183,6 +1183,88 @@
(const_int 1)))]
)
+(define_expand "save_stack_nonlocal"
+ [(set (match_operand 0 "memory_operand")
+ (match_operand 1 "register_operand"))]
+ ""
+{
+ rtx stack_slot = adjust_address (operands[0], Pmode, 0);
+ emit_move_insn (stack_slot, operands[1]);
+
+ if (aarch64_gcs_enabled ())
+ {
+ /* Save GCS with code like
+ mov x16, 1
+ chkfeat x16
+ tbnz x16, 0, .L_done
+ mrs tmp, gcspr_el0
+ str tmp, [%0, 8]
+ .L_done: */
+
+ rtx done_label = gen_label_rtx ();
+ rtx r16 = gen_rtx_REG (DImode, R16_REGNUM);
+ emit_move_insn (r16, const1_rtx);
+ emit_insn (gen_aarch64_chkfeat ());
+ emit_insn (gen_tbranch_neqi3 (r16, const0_rtx, done_label));
+ rtx gcs_slot = adjust_address (operands[0], Pmode, GET_MODE_SIZE (Pmode));
+ rtx gcs = force_reg (Pmode, const0_rtx);
+ emit_insn (gen_aarch64_load_gcspr (gcs));
+ emit_move_insn (gcs_slot, gcs);
+ emit_label (done_label);
+ }
+ DONE;
+})
+
+(define_expand "restore_stack_nonlocal"
+ [(set (match_operand 0 "register_operand" "")
+ (match_operand 1 "memory_operand" ""))]
+ ""
+{
+ rtx stack_slot = adjust_address (operands[1], Pmode, 0);
+ emit_move_insn (operands[0], stack_slot);
+
+ if (aarch64_gcs_enabled ())
+ {
+ /* Restore GCS with code like
+ mov x16, 1
+ chkfeat x16
+ tbnz x16, 0, .L_done
+ ldr tmp1, [%1, 8]
+ mrs tmp2, gcspr_el0
+ subs tmp2, tmp1, tmp2
+ b.eq .L_done
+ .L_loop:
+ gcspopm
+ subs tmp2, tmp2, 8
+ b.ne .L_loop
+ .L_done: */
+
+ rtx loop_label = gen_label_rtx ();
+ rtx done_label = gen_label_rtx ();
+ rtx r16 = gen_rtx_REG (DImode, R16_REGNUM);
+ emit_move_insn (r16, const1_rtx);
+ emit_insn (gen_aarch64_chkfeat ());
+ emit_insn (gen_tbranch_neqi3 (r16, const0_rtx, done_label));
+ rtx gcs_slot = adjust_address (operands[1], Pmode, GET_MODE_SIZE (Pmode));
+ rtx gcs_old = force_reg (Pmode, const0_rtx);
+ emit_move_insn (gcs_old, gcs_slot);
+ rtx gcs_now = force_reg (Pmode, const0_rtx);
+ emit_insn (gen_aarch64_load_gcspr (gcs_now));
+ emit_insn (gen_subdi3_compare1 (gcs_now, gcs_old, gcs_now));
+ rtx cc_reg = gen_rtx_REG (CC_NZmode, CC_REGNUM);
+ rtx cmp_rtx = gen_rtx_fmt_ee (EQ, DImode, cc_reg, const0_rtx);
+ emit_jump_insn (gen_condjump (cmp_rtx, cc_reg, done_label));
+ emit_label (loop_label);
+ emit_insn (gen_aarch64_gcspopm_xzr ());
+ emit_insn (gen_adddi3_compare0 (gcs_now, gcs_now, GEN_INT (-8)));
+ cc_reg = gen_rtx_REG (CC_NZmode, CC_REGNUM);
+ cmp_rtx = gen_rtx_fmt_ee (NE, DImode, cc_reg, const0_rtx);
+ emit_jump_insn (gen_condjump (cmp_rtx, cc_reg, loop_label));
+ emit_label (done_label);
+ }
+ DONE;
+})
+
;; -------------------------------------------------------------------
;; Subroutine calls and sibcalls
;; -------------------------------------------------------------------
--
2.34.1
From 44b1847be5f2a53727a4a64f2d895b1c1d65e460 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed, 7 Jun 2023 10:58:06 +0100
Subject: [PATCH 11/19] aarch64: Add non-local goto and jump tests for GCS
These are scan asm tests only, relying on existing execution tests
for runtime coverage.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/gcs-nonlocal-1.c: New test.
* gcc.target/aarch64/gcs-nonlocal-2.c: New test.
---
.../gcc.target/aarch64/gcs-nonlocal-1.c | 25 +++++++++++++++++++
.../gcc.target/aarch64/gcs-nonlocal-2.c | 21 ++++++++++++++++
2 files changed, 46 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-2.c
diff --git a/gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-1.c b/gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-1.c
new file mode 100644
index 00000000000..821fab816f9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-1.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbranch-protection=gcs" } */
+/* { dg-final { scan-assembler-times "hint\\t40 // chkfeat x16" 2 } } */
+/* { dg-final { scan-assembler-times "mrs\\tx\[0-9\]+, s3_3_c2_c5_1 // gcspr_el0" 2 } } */
+/* { dg-final { scan-assembler-times "sysl\\txzr, #3, c7, c7, #1 // gcspopm" 1 } } */
+
+int bar1 (int);
+int bar2 (int);
+
+void foo (int cmd)
+{
+ __label__ start;
+ int x = 0;
+
+ void nonlocal_goto (void)
+ {
+ x++;
+ goto start;
+ }
+
+start:
+ while (bar1 (x))
+ if (bar2 (x))
+ nonlocal_goto ();
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-2.c b/gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-2.c
new file mode 100644
index 00000000000..63dbce36e1e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/gcs-nonlocal-2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbranch-protection=gcs" } */
+/* { dg-final { scan-assembler-times "hint\\t40 // chkfeat x16" 2 } } */
+/* { dg-final { scan-assembler-times "mrs\\tx\[0-9\]+, s3_3_c2_c5_1 // gcspr_el0" 2 } } */
+/* { dg-final { scan-assembler-times "sysl\\txzr, #3, c7, c7, #1 // gcspopm" 1 } } */
+
+void longj (void *buf)
+{
+ __builtin_longjmp (buf, 1);
+}
+
+void foo (void);
+void bar (void);
+
+void setj (void *buf)
+{
+ if (__builtin_setjmp (buf))
+ foo ();
+ else
+ bar ();
+}
--
2.34.1
From a9ec10c065ac9d932e30de54d68363f30ed864fe Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 9 May 2023 17:04:34 +0100
Subject: [PATCH 12/19] aarch64: Add ACLE feature macros for GCS
gcc/ChangeLog:
* config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): Define
macros for GCS.
---
gcc/config/aarch64/aarch64-c.cc | 3 +++
1 file changed, 3 insertions(+)
diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc
index b5a6917d06d..132d5c86413 100644
--- a/gcc/config/aarch64/aarch64-c.cc
+++ b/gcc/config/aarch64/aarch64-c.cc
@@ -246,6 +246,9 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
aarch64_def_or_undef (TARGET_PAUTH, "__ARM_FEATURE_PAUTH", pfile);
aarch64_def_or_undef (TARGET_BTI, "__ARM_FEATURE_BTI", pfile);
+ aarch64_def_or_undef (aarch64_gcs_enabled (),
+ "__ARM_FEATURE_GCS_DEFAULT", pfile);
+ aarch64_def_or_undef (TARGET_GCS, "__ARM_FEATURE_GCS", pfile);
aarch64_def_or_undef (TARGET_I8MM, "__ARM_FEATURE_MATMUL_INT8", pfile);
aarch64_def_or_undef (TARGET_BF16_SIMD,
"__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", pfile);
--
2.34.1
From ff3d447772dcf9b2c7293a6b1ac458898a493cdf Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed, 7 Jun 2023 16:17:53 +0100
Subject: [PATCH 13/19] aarch64: Add test for GCS ACLE defs
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/pragma_cpp_predefs_1.c: GCS test.
---
.../gcc.target/aarch64/pragma_cpp_predefs_1.c | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c
index 307fa3d67da..6122cd55d66 100644
--- a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c
@@ -268,6 +268,36 @@
#error "__ARM_FEATURE_RCPC is not defined but should be!"
#endif
+#pragma GCC target ("arch=armv8.8-a+gcs")
+#ifndef __ARM_FEATURE_GCS
+#error "__ARM_FEATURE_GCS is not defined but should be!"
+#endif
+
+#pragma GCC target ("arch=armv8.8-a+nogcs")
+#ifdef __ARM_FEATURE_GCS
+#error "__ARM_FEATURE_GCS is defined but should not be!"
+#endif
+
+#pragma GCC target ("arch=armv8.8-a")
+#ifdef __ARM_FEATURE_GCS
+#error "__ARM_FEATURE_GCS is defined but should not be!"
+#endif
+
+#pragma GCC target ("branch-protection=gcs")
+#ifndef __ARM_FEATURE_GCS_DEFAULT
+#error "__ARM_FEATURE_GCS_DEFAULT is not defined but should be!"
+#endif
+
+#pragma GCC target ("branch-protection=none")
+#ifdef __ARM_FEATURE_GCS_DEFAULT
+#error "__ARM_FEATURE_GCS_DEFAULT is defined but should not be!"
+#endif
+
+#pragma GCC target ("branch-protection=standard")
+#ifndef __ARM_FEATURE_GCS_DEFAULT
+#error "__ARM_FEATURE_GCS_DEFAULT is not defined but should be!"
+#endif
+
int
foo (int a)
{
--
2.34.1
From 8187d08bc815c5d45fa5b7cc6a970811ca4c6efe Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed, 19 Apr 2023 14:01:36 +0100
Subject: [PATCH 14/19] aarch64: Add GCS support to the unwinder
TODO:
- Follows the current linux ABI that uses single signal entry token
and shared shadow stack between thread and alt stack.
- Could be behind __ARM_FEATURE_GCS_DEFAULT ifdef (only do anything
special with gcs compat codegen) but there is a runtime check anyway.
libgcc/ChangeLog:
* config/aarch64/aarch64-unwind.h (_Unwind_Frames_Extra): Update.
(_Unwind_Frames_Increment): Define.
---
libgcc/config/aarch64/aarch64-unwind.h | 59 +++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
index daf96624b5e..c22a3fc20d2 100644
--- a/libgcc/config/aarch64/aarch64-unwind.h
+++ b/libgcc/config/aarch64/aarch64-unwind.h
@@ -78,6 +78,9 @@ aarch64_demangle_return_addr (struct _Unwind_Context *context,
return addr;
}
+/* GCS enable flag for chkfeat instruction. */
+#define CHKFEAT_GCS 1
+
/* SME runtime function local to libgcc, streaming compatible
and preserves more registers than the base PCS requires, but
we don't rely on that here. */
@@ -85,12 +88,66 @@ __attribute__ ((visibility ("hidden")))
void __libgcc_arm_za_disable (void);
/* Disable the SME ZA state in case an unwound frame used the ZA
- lazy saving scheme. */
+ lazy saving scheme. And unwind the GCS for EH. */
#undef _Unwind_Frames_Extra
#define _Unwind_Frames_Extra(x) \
do \
{ \
__libgcc_arm_za_disable (); \
+ if (__builtin_aarch64_chkfeat (CHKFEAT_GCS) == 0) \
+ { \
+ for (_Unwind_Word n = (x); n != 0; n--) \
+ __builtin_aarch64_gcspopm (); \
+ } \
+ } \
+ while (0)
+
+/* On signal entry the OS places a token on the GCS that can be used to
+ verify the integrity of the GCS pointer on signal return. It also
+ places the signal handler return address (the restorer that calls the
+ signal return syscall) on the GCS so the handler can return.
+ Because of this token, each stack frame visited during unwinding has
+ exactly one corresponding entry on the GCS, so the frame count is
+ the number of entries that will have to be popped at EH return time.
+
+ Note: This depends on the GCS signal ABI of the OS.
+
+ When unwinding across a stack frame for each frame the corresponding
+ entry is checked on the GCS against the computed return address from
+ the normal stack. If they don't match then _URC_FATAL_PHASE2_ERROR
+ is returned. This check is omitted if
+
+ 1. GCS is disabled. Note: asynchronous GCS disable is supported here
+ if GCSPR and the GCS remains readable.
+ 2. Non-catchable exception where exception_class == 0. Note: the
+ pthread cancellation implementation in glibc sets exception_class
+ to 0 when the unwinder is used for cancellation cleanup handling,
+ so this allows the GCS to get out of sync during cancellation.
+ This weakens security but avoids an ABI break in glibc.
+ 3. Zero return address which marks the outermost stack frame.
+ 4. Signal stack frame, the GCS entry is an OS specific token then
+ with the top bit set.
+ */
+#undef _Unwind_Frames_Increment
+#define _Unwind_Frames_Increment(exc, context, frames) \
+ do \
+ { \
+ frames++; \
+ if (__builtin_aarch64_chkfeat (CHKFEAT_GCS) != 0 \
+ || exc->exception_class == 0 \
+ || _Unwind_GetIP (context) == 0) \
+ break; \
+ const _Unwind_Word *gcs = __builtin_aarch64_gcspr (); \
+ if (_Unwind_IsSignalFrame (context)) \
+ { \
+ if (gcs[frames] >> 63 == 0) \
+ return _URC_FATAL_PHASE2_ERROR; \
+ } \
+ else \
+ { \
+ if (gcs[frames] != _Unwind_GetIP (context)) \
+ return _URC_FATAL_PHASE2_ERROR; \
+ } \
} \
while (0)
--
2.34.1
From f183fe2dd597f300b24151034d68d168401ab83e Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 9 May 2023 14:32:46 +0100
Subject: [PATCH 15/19] aarch64: Emit GNU property NOTE for GCS
TODO: relies on experimental binutils ABI, should use build attributes.
gcc/ChangeLog:
* config/aarch64/aarch64.cc (GNU_PROPERTY_AARCH64_FEATURE_1_GCS):
Define.
(aarch64_file_end_indicate_exec_stack): Set GCS property bit.
---
gcc/config/aarch64/aarch64.cc | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 73969721906..0119cfdd67b 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -28962,6 +28962,7 @@ aarch64_can_tag_addresses ()
#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0)
#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1U << 1)
+#define GNU_PROPERTY_AARCH64_FEATURE_1_GCS (1U << 2)
void
aarch64_file_end_indicate_exec_stack ()
{
@@ -28974,6 +28975,9 @@ aarch64_file_end_indicate_exec_stack ()
if (aarch_ra_sign_scope != AARCH_FUNCTION_NONE)
feature_1_and |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+ if (aarch64_gcs_enabled ())
+ feature_1_and |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+
if (feature_1_and)
{
/* Generate .note.gnu.property section. */
@@ -29005,6 +29009,7 @@ aarch64_file_end_indicate_exec_stack ()
assemble_align (POINTER_SIZE);
}
}
+#undef GNU_PROPERTY_AARCH64_FEATURE_1_GCS
#undef GNU_PROPERTY_AARCH64_FEATURE_1_PAC
#undef GNU_PROPERTY_AARCH64_FEATURE_1_BTI
#undef GNU_PROPERTY_AARCH64_FEATURE_1_AND
--
2.34.1
From 966dbf5b1816a49eebc7b9a52abe706e34ee67d3 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Fri, 22 Dec 2023 13:44:19 +0000
Subject: [PATCH 16/19] aarch64: libgcc: add GCS marking to asm
libgcc/ChangeLog:
* config/aarch64/aarch64-asm.h (FEATURE_1_GCS): Define.
(GCS_FLAG): Define if GCS is enabled.
(GNU_PROPERTY): Add GCS_FLAG.
---
libgcc/config/aarch64/aarch64-asm.h | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/libgcc/config/aarch64/aarch64-asm.h b/libgcc/config/aarch64/aarch64-asm.h
index 83c2e5944b3..86a9a0e662e 100644
--- a/libgcc/config/aarch64/aarch64-asm.h
+++ b/libgcc/config/aarch64/aarch64-asm.h
@@ -38,6 +38,7 @@
#define FEATURE_1_AND 0xc0000000
#define FEATURE_1_BTI 1
#define FEATURE_1_PAC 2
+#define FEATURE_1_GCS 4
/* Supported features based on the code generation options. */
#if defined(__ARM_FEATURE_BTI_DEFAULT)
@@ -58,6 +59,12 @@
# define AUTIASP
#endif
+#if __ARM_FEATURE_GCS_DEFAULT
+# define GCS_FLAG FEATURE_1_GCS
+#else
+# define GCS_FLAG 0
+#endif
+
#ifdef __ELF__
#define HIDDEN(name) .hidden name
#define SYMBOL_SIZE(name) .size name, .-name
@@ -88,8 +95,8 @@
.previous
/* Add GNU property note if built with branch protection. */
-# if (BTI_FLAG|PAC_FLAG) != 0
-GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG)
+# if (BTI_FLAG|PAC_FLAG|GCS_FLAG) != 0
+GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG|GCS_FLAG)
# endif
#endif
--
2.34.1
From bb609f49cbd69259513d9c39a74ad61730e3c87a Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Fri, 22 Dec 2023 15:11:25 +0000
Subject: [PATCH 17/19] aarch64: libatomic: add GCS marking to asm
libatomic/ChangeLog:
* config/linux/aarch64/atomic_16.S (FEATURE_1_GCS): Define.
(GCS_FLAG): Define if GCS is enabled.
(GNU_PROPERTY): Add GCS_FLAG.
---
libatomic/config/linux/aarch64/atomic_16.S | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/libatomic/config/linux/aarch64/atomic_16.S b/libatomic/config/linux/aarch64/atomic_16.S
index 4e3fa870b03..d6f34eee146 100644
--- a/libatomic/config/linux/aarch64/atomic_16.S
+++ b/libatomic/config/linux/aarch64/atomic_16.S
@@ -790,6 +790,7 @@ ALIAS2 (test_and_set_16)
#define FEATURE_1_AND 0xc0000000
#define FEATURE_1_BTI 1
#define FEATURE_1_PAC 2
+#define FEATURE_1_GCS 4
/* Supported features based on the code generation options. */
#if defined(__ARM_FEATURE_BTI_DEFAULT)
@@ -804,6 +805,12 @@ ALIAS2 (test_and_set_16)
# define PAC_FLAG 0
#endif
+#if __ARM_FEATURE_GCS_DEFAULT
+# define GCS_FLAG FEATURE_1_GCS
+#else
+# define GCS_FLAG 0
+#endif
+
/* Add a NT_GNU_PROPERTY_TYPE_0 note. */
#define GNU_PROPERTY(type, value) \
.section .note.gnu.property, "a"; \
@@ -821,7 +828,7 @@ ALIAS2 (test_and_set_16)
.section .note.GNU-stack, "", %progbits
/* Add GNU property note if built with branch protection. */
-# if (BTI_FLAG|PAC_FLAG) != 0
-GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG)
+# if (BTI_FLAG|PAC_FLAG|GCS_FLAG) != 0
+GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG|GCS_FLAG)
# endif
#endif
--
2.34.1
From 1d54b68e7c410b83fec17708ee84e7c64a461d3d Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue, 2 Apr 2024 15:43:23 +0100
Subject: [PATCH 18/19] aarch64: libitm: Add GCS support
Transaction begin and abort use setjmp/longjmp like operations that
need to be updated for GCS compatibility. We use similar logic to
libc setjmp/longjmp that support switching stack and thus switching
GCS (e.g. due to longjmp out of a makecontext stack), this is kept
even though it is likely not required for transaction aborts.
The gtm_jmpbuf is internal to libitm so we can change its layout
without breaking ABI.
libitm/ChangeLog:
* config/aarch64/sjlj.S: Add GCS support and mark GCS compatible.
* config/aarch64/target.h: Add gcs field to gtm_jmpbuf.
---
libitm/config/aarch64/sjlj.S | 60 ++++++++++++++++++++++++++++++++--
libitm/config/aarch64/target.h | 1 +
2 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/libitm/config/aarch64/sjlj.S b/libitm/config/aarch64/sjlj.S
index 6b248f7c040..e21d751ef21 100644
--- a/libitm/config/aarch64/sjlj.S
+++ b/libitm/config/aarch64/sjlj.S
@@ -29,6 +29,13 @@
#define AUTIASP hint 29
#define PACIBSP hint 27
#define AUTIBSP hint 31
+#define CHKFEAT_X16 hint 40
+#define MRS_GCSPR(x) mrs x, s3_3_c2_c5_1
+#define GCSPOPM(x) sysl x, #3, c7, c7, #1
+#define GCSSS1(x) sys #3, c7, c7, #2, x
+#define GCSSS2(x) sysl x, #3, c7, c7, #3
+
+#define L(name) .L##name
#if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
# define cfi_window_save .cfi_window_save
@@ -80,7 +87,16 @@ _ITM_beginTransaction:
stp d10, d11, [sp, 7*16]
stp d12, d13, [sp, 8*16]
stp d14, d15, [sp, 9*16]
- str x1, [sp, 10*16]
+
+ /* GCS support. */
+ mov x2, 0
+ mov x16, 1
+ CHKFEAT_X16
+ tbnz x16, 0, L(gcs_done_sj)
+ MRS_GCSPR (x2)
+ add x2, x2, 8 /* GCS after _ITM_beginTransaction returns. */
+L(gcs_done_sj):
+ stp x2, x1, [sp, 10*16]
/* Invoke GTM_begin_transaction with the struct we just built. */
mov x1, sp
@@ -117,7 +133,38 @@ GTM_longjmp:
ldp d10, d11, [x1, 7*16]
ldp d12, d13, [x1, 8*16]
ldp d14, d15, [x1, 9*16]
+
+ /* GCS support. */
+ mov x16, 1
+ CHKFEAT_X16
+ tbnz x16, 0, L(gcs_done_lj)
+ MRS_GCSPR (x7)
ldr x3, [x1, 10*16]
+ mov x4, x3
+ /* x7: GCSPR now. x3, x4: target GCSPR. x5, x6: tmp regs. */
+L(gcs_scan):
+ cmp x7, x4
+ b.eq L(gcs_pop)
+ sub x4, x4, 8
+ /* Check for a cap token. */
+ ldr x5, [x4]
+ and x6, x4, 0xfffffffffffff000
+ orr x6, x6, 1
+ cmp x5, x6
+ b.ne L(gcs_scan)
+L(gcs_switch):
+ add x7, x4, 8
+ GCSSS1 (x4)
+ GCSSS2 (xzr)
+L(gcs_pop):
+ cmp x7, x3
+ b.eq L(gcs_done_lj)
+ GCSPOPM (xzr)
+ add x7, x7, 8
+ b L(gcs_pop)
+L(gcs_done_lj):
+
+ ldr x3, [x1, 10*16 + 8]
ldp x29, x30, [x1]
cfi_def_cfa(x1, 0)
CFI_PAC_TOGGLE
@@ -132,6 +179,7 @@ GTM_longjmp:
#define FEATURE_1_AND 0xc0000000
#define FEATURE_1_BTI 1
#define FEATURE_1_PAC 2
+#define FEATURE_1_GCS 4
/* Supported features based on the code generation options. */
#if defined(__ARM_FEATURE_BTI_DEFAULT)
@@ -146,6 +194,12 @@ GTM_longjmp:
# define PAC_FLAG 0
#endif
+#if __ARM_FEATURE_GCS_DEFAULT
+# define GCS_FLAG FEATURE_1_GCS
+#else
+# define GCS_FLAG 0
+#endif
+
/* Add a NT_GNU_PROPERTY_TYPE_0 note. */
#define GNU_PROPERTY(type, value) \
.section .note.gnu.property, "a"; \
@@ -163,7 +217,7 @@ GTM_longjmp:
.section .note.GNU-stack, "", %progbits
/* Add GNU property note if built with branch protection. */
-# if (BTI_FLAG|PAC_FLAG) != 0
-GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG)
+# if (BTI_FLAG|PAC_FLAG|GCS_FLAG) != 0
+GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG|GCS_FLAG)
# endif
#endif
diff --git a/libitm/config/aarch64/target.h b/libitm/config/aarch64/target.h
index 3d99197bfab..a1f39b4bf7a 100644
--- a/libitm/config/aarch64/target.h
+++ b/libitm/config/aarch64/target.h
@@ -30,6 +30,7 @@ typedef struct gtm_jmpbuf
unsigned long long pc; /* x30 */
unsigned long long gr[10]; /* x19-x28 */
unsigned long long vr[8]; /* d8-d15 */
+ void *gcs; /* GCSPR_EL0 */
void *cfa;
} gtm_jmpbuf;
--
2.34.1
From c3a32ae0e30d2f4c51659751bc784b1c84ca1351 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu, 28 Dec 2023 13:37:38 +0000
Subject: [PATCH 19/19] aarch64: Introduce indirect_return attribute
Tail calls of indirect_return functions from non-indirect_return
functions are disallowed even if BTI is disabled, since the call
site may have BTI enabled.
Following x86, mismatching attribute on function pointers is not
a type error even though this can lead to bugs.
Needed for swapcontext within the same function when GCS is enabled.
TODO: arm? docs, tests. feature detection?
gcc/ChangeLog:
* config/aarch64/aarch64.cc (aarch64_gnu_attributes): Add
indirect_return.
(aarch64_function_ok_for_sibcall): Disallow tail calls if caller
is non-indirect_return but callee is indirect_return.
(aarch64_comp_type_attributes): Check indirect_return attribute.
* config/arm/aarch-bti-insert.cc (call_needs_bti_j): New.
(rest_of_insert_bti): Use call_needs_bti_j.
---
gcc/config/aarch64/aarch64.cc | 11 +++++++++
gcc/config/arm/aarch-bti-insert.cc | 36 ++++++++++++++++++++++++++----
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0119cfdd67b..593b107c8a5 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -850,6 +850,7 @@ static const attribute_spec aarch64_gnu_attributes[] =
affects_type_identity, handler, exclude } */
{ "aarch64_vector_pcs", 0, 0, false, true, true, true,
handle_aarch64_vector_pcs_attribute, NULL },
+ { "indirect_return", 0, 0, false, true, true, false, NULL, NULL },
{ "arm_sve_vector_bits", 1, 1, false, true, false, true,
aarch64_sve::handle_arm_sve_vector_bits_attribute,
NULL },
@@ -6340,6 +6341,14 @@ aarch64_function_ok_for_sibcall (tree, tree exp)
if (bool (aarch64_cfun_shared_flags (state))
!= bool (aarch64_fntype_shared_flags (fntype, state)))
return false;
+
+ /* BTI J is needed where indirect_return functions may return
+ if bti is enabled there. */
+ if (lookup_attribute ("indirect_return", TYPE_ATTRIBUTES (fntype))
+ && !lookup_attribute ("indirect_return",
+ TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))))
+ return false;
+
return true;
}
@@ -28855,6 +28864,8 @@ aarch64_comp_type_attributes (const_tree type1, const_tree type2)
if (!check_attr ("gnu", "aarch64_vector_pcs"))
return 0;
+ if (!check_attr ("gnu", "indirect_return"))
+ return 0;
if (!check_attr ("gnu", "Advanced SIMD type"))
return 0;
if (!check_attr ("gnu", "SVE type"))
diff --git a/gcc/config/arm/aarch-bti-insert.cc b/gcc/config/arm/aarch-bti-insert.cc
index 14d36971cd4..403afff9120 100644
--- a/gcc/config/arm/aarch-bti-insert.cc
+++ b/gcc/config/arm/aarch-bti-insert.cc
@@ -92,6 +92,35 @@ const pass_data pass_data_insert_bti =
0, /* todo_flags_finish. */
};
+/* Decide if BTI J is needed after a call instruction. */
+static bool
+call_needs_bti_j (rtx_insn *insn)
+{
+ /* Call returns twice, one of which may be indirect. */
+ if (find_reg_note (insn, REG_SETJMP, NULL))
+ return true;
+
+ /* Tail call does not return. */
+ if (SIBLING_CALL_P (insn))
+ return false;
+
+ /* Check if the function is marked to return indirectly. */
+ rtx call = get_call_rtx_from (insn);
+ rtx fnaddr = XEXP (call, 0);
+ tree fndecl = NULL_TREE;
+ if (GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
+ fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
+ if (fndecl == NULL_TREE)
+ fndecl = MEM_EXPR (fnaddr);
+ if (!fndecl)
+ return false;
+ if (TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
+ return false;
+ tree fntype = TREE_TYPE (fndecl);
+ return lookup_attribute ("indirect_return", TYPE_ATTRIBUTES (fntype));
+}
+
/* Insert the BTI instruction. */
/* This is implemented as a late RTL pass that runs before branch
shortening and does the following. */
@@ -147,10 +176,9 @@ rest_of_insert_bti (void)
}
}
- /* 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)))
+ /* Also look for calls that may return indirectly, such as setjmp,
+ and put a BTI J after them. */
+ if (CALL_P (insn) && call_needs_bti_j (insn))
{
bti_insn = aarch_gen_bti_j ();
emit_insn_after (bti_insn, insn);
--
2.34.1