about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-09-24 13:04:19 +0000
committerbors <bors@rust-lang.org>2025-09-24 13:04:19 +0000
commit15283f6fe95e5b604273d13a428bab5fc0788f5a (patch)
tree0dc36ced16f62c9c3445da41a4d9866ff73b3071
parente9385f9eea0221ef295a188d49d16f8f5189abf1 (diff)
parent08020def99d2851af0dabde12cc6d203017fa72c (diff)
downloadrust-15283f6fe95e5b604273d13a428bab5fc0788f5a.tar.gz
rust-15283f6fe95e5b604273d13a428bab5fc0788f5a.zip
Auto merge of #146338 - CrooseGit:dev/reucru01/AArch64-enable-GCS, r=Urgau,davidtwco
Extends AArch64 branch protection support to include GCS

Extends existing support for AArch64 branch protection to include support for [Guarded Control Stacks](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/arm-a-profile-architecture-2022#guarded-control-stack-gcs:~:text=Extraction%20or%20tracking.-,Guarded%20Control%20Stack%20(GCS),-With%20the%202022).
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs9
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_session/src/config.rs1
-rw-r--r--compiler/rustc_session/src/options.rs3
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile2
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile2
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/branch-protection.md1
-rw-r--r--tests/assembly-llvm/aarch64-pointer-auth.rs6
-rw-r--r--tests/codegen-llvm/branch-protection.rs6
-rw-r--r--tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs8
-rw-r--r--tests/run-make/pointer-auth-link-with-c/rmake.rs10
-rw-r--r--tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr2
-rw-r--r--tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr2
15 files changed, 44 insertions, 18 deletions
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 573c51a9539..dcf6b945497 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -407,13 +407,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
 
         // For non-naked functions, set branch protection attributes on aarch64.
-        if let Some(BranchProtection { bti, pac_ret }) =
+        if let Some(BranchProtection { bti, pac_ret, gcs }) =
             cx.sess().opts.unstable_opts.branch_protection
         {
             assert!(cx.sess().target.arch == "aarch64");
             if bti {
                 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
             }
+            if gcs {
+                to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack"));
+            }
             if let Some(PacRet { leaf, pc, key }) = pac_ret {
                 if pc {
                     to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr"));
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 4a8ea11a3a8..057f525c76f 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -370,7 +370,8 @@ pub(crate) unsafe fn create_module<'ll>(
         );
     }
 
-    if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
+    if let Some(BranchProtection { bti, pac_ret, gcs }) = sess.opts.unstable_opts.branch_protection
+    {
         if sess.target.arch == "aarch64" {
             llvm::add_module_flag_u32(
                 llmod,
@@ -403,6 +404,12 @@ pub(crate) unsafe fn create_module<'ll>(
                 "sign-return-address-with-bkey",
                 u32::from(pac_opts.key == PAuthKey::B),
             );
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Min,
+                "guarded-control-stack",
+                gcs.into(),
+            );
         } else {
             bug!(
                 "branch-protection used on non-AArch64 target; \
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 7730bddc0f1..800f5efee41 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -772,7 +772,8 @@ fn test_unstable_options_tracking_hash() {
         branch_protection,
         Some(BranchProtection {
             bti: true,
-            pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B })
+            pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }),
+            gcs: true,
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 81ada79dd43..ebb6a93b1dd 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1621,6 +1621,7 @@ pub struct PacRet {
 pub struct BranchProtection {
     pub bti: bool,
     pub pac_ret: Option<PacRet>,
+    pub gcs: bool,
 }
 
 pub(crate) const fn default_lib_output() -> CrateType {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 3b9d8117786..b2cc169f12c 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -866,7 +866,7 @@ mod desc {
     pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`";
     pub(crate) const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
-    pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`";
+    pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)";
     pub(crate) const parse_proc_macro_execution_strategy: &str =
         "one of supported execution strategies (`same-thread`, or `cross-thread`)";
     pub(crate) const parse_remap_path_scope: &str =
@@ -1905,6 +1905,7 @@ pub mod parse {
                             Some(pac) => pac.pc = true,
                             _ => return false,
                         },
+                        "gcs" => slot.gcs = true,
                         _ => return false,
                     };
                 }
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
index 71de8f917fa..04b46226acf 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:25.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile
index adbb1f03378..095624d6fb7 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:25.04
+FROM ubuntu:25.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
index e6133fce83e..4b61fd94a6c 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:25.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
diff --git a/src/doc/unstable-book/src/compiler-flags/branch-protection.md b/src/doc/unstable-book/src/compiler-flags/branch-protection.md
index f0cc44a07f3..c15567dcac2 100644
--- a/src/doc/unstable-book/src/compiler-flags/branch-protection.md
+++ b/src/doc/unstable-book/src/compiler-flags/branch-protection.md
@@ -13,6 +13,7 @@ It takes some combination of the following values, separated by a `,`.
 - `leaf` - Enable pointer authentication for all functions, including leaf functions.
 - `b-key` - Sign return addresses with key B, instead of the default key A.
 - `bti` - Enable branch target identification.
+- `gcs` - Enable guarded control stack support.
 
 `leaf`, `b-key` and `pc` are only valid if `pac-ret` was previously specified.
 For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but
diff --git a/tests/assembly-llvm/aarch64-pointer-auth.rs b/tests/assembly-llvm/aarch64-pointer-auth.rs
index 56a26df469f..e1ca6d77581 100644
--- a/tests/assembly-llvm/aarch64-pointer-auth.rs
+++ b/tests/assembly-llvm/aarch64-pointer-auth.rs
@@ -1,10 +1,13 @@
 // Test that PAC instructions are emitted when branch-protection is specified.
 
 //@ add-core-stubs
-//@ revisions: PACRET PAUTHLR_NOP PAUTHLR
+//@ revisions: GCS PACRET PAUTHLR_NOP PAUTHLR
 //@ assembly-output: emit-asm
 //@ needs-llvm-components: aarch64
 //@ compile-flags: --target aarch64-unknown-linux-gnu
+//@ [GCS] min-llvm-version: 21
+//@ [GCS] ignore-apple (XCode version needs updating)
+//@ [GCS] compile-flags: -Z branch-protection=gcs
 //@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf
 //@ [PAUTHLR_NOP] compile-flags: -Z branch-protection=pac-ret,pc,leaf
 //@ [PAUTHLR] compile-flags: -C target-feature=+pauth-lr -Z branch-protection=pac-ret,pc,leaf
@@ -17,6 +20,7 @@
 extern crate minicore;
 use minicore::*;
 
+// GCS: .aeabi_attribute 2, 1 // Tag_Feature_GCS
 // PACRET: hint #25
 // PACRET: hint #29
 // PAUTHLR_NOP: hint #25
diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs
index d67e494cc0d..f92259c941c 100644
--- a/tests/codegen-llvm/branch-protection.rs
+++ b/tests/codegen-llvm/branch-protection.rs
@@ -1,9 +1,10 @@
 // Test that the correct module flags are emitted with different branch protection flags.
 
 //@ add-core-stubs
-//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE
+//@ revisions: BTI GCS PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE
 //@ needs-llvm-components: aarch64
 //@ [BTI] compile-flags: -Z branch-protection=bti
+//@ [GCS] compile-flags: -Z branch-protection=gcs
 //@ [PACRET] compile-flags: -Z branch-protection=pac-ret
 //@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf
 //@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key
@@ -32,6 +33,9 @@ pub fn test() {}
 // BTI: !"sign-return-address-all", i32 0
 // BTI: !"sign-return-address-with-bkey", i32 0
 
+// GCS: attributes [[ATTR]] = {{.*}} "guarded-control-stack"
+// GCS: !"guarded-control-stack", i32 1
+
 // PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
 // PACRET-SAME: "sign-return-address-key"="a_key"
 // PACRET: !"branch-target-enforcement", i32 0
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
index 0a2186b0953..2ac5fdee063 100644
--- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
@@ -1,12 +1,14 @@
 // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication
 // code (PAC), a useful hashing measure for verifying that pointers have not been modified.
 // This test checks that compilation and execution is successful when this feature is activated,
-// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO.
+// with some of its possible extra arguments (bti, gcs, pac-ret, leaf) when doing LTO.
 // See https://github.com/rust-lang/rust/pull/88354
 
 //@ needs-force-clang-based-tests
 //@ only-aarch64
 // Reason: branch protection is not supported on other architectures
+//@ ignore-apple
+// Reason: XCode needs updating to support gcs
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
@@ -19,7 +21,7 @@ fn main() {
     clang()
         .arg("-v")
         .lto("thin")
-        .arg("-mbranch-protection=bti+pac-ret+b-key+leaf")
+        .arg("-mbranch-protection=bti+gcs+pac-ret+b-key+leaf")
         .arg("-c")
         .out_exe("test.o")
         .input("test.c")
@@ -30,7 +32,7 @@ fn main() {
         .opt_level("2")
         .linker(&env_var("CLANG"))
         .link_arg("-fuse-ld=lld")
-        .arg("-Zbranch-protection=bti,pac-ret,leaf")
+        .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf")
         .input("test.rs")
         .output("test.bin")
         .run();
diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs
index a4d7454e575..1ddcb79d64f 100644
--- a/tests/run-make/pointer-auth-link-with-c/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs
@@ -1,11 +1,13 @@
 // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication
 // code (PAC), a useful hashing measure for verifying that pointers have not been modified.
 // This test checks that compilation and execution is successful when this feature is activated,
-// with some of its possible extra arguments (bti, pac-ret, pc, leaf, b-key).
+// with some of its possible extra arguments (bti, gcs, pac-ret, pc, leaf, b-key).
 // See https://github.com/rust-lang/rust/pull/88354
 
 //@ only-aarch64
 // Reason: branch protection is not supported on other architectures
+//@ ignore-apple
+// Reason: XCode needs updating to support gcs
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
@@ -13,17 +15,17 @@ use run_make_support::{build_native_static_lib, cc, is_windows_msvc, llvm_ar, ru
 
 fn main() {
     build_native_static_lib("test");
-    rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run();
+    rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run();
     run("test");
     cc().arg("-v")
         .arg("-c")
         .out_exe("test")
         .input("test.c")
-        .arg("-mbranch-protection=bti+pac-ret+leaf")
+        .arg("-mbranch-protection=bti+gcs+pac-ret+leaf")
         .run();
     let obj_file = if is_windows_msvc() { "test.obj" } else { "test" };
     llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run();
-    rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run();
+    rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run();
     run("test");
 
     // FIXME: +pc was only recently added to LLVM
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
index dae08119dbc..277111a41f2 100644
--- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
+++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected
+error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected
 
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
index 13f79e94674..e1ade01d2fe 100644
--- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
+++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected
+error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected