From b368dcb246c5aedb087034e0f62941d038799f38 Mon Sep 17 00:00:00 2001
From: Ding Xiang Fei <dingxiangfei2009@protonmail.ch>
Date: Mon, 29 Jul 2024 23:10:34 +0800
Subject: [PATCH] unconditionally allow shadow call-stack for AArch64 whenever
 fixed-x18 is applied

---
 compiler/rustc_session/src/session.rs         |  7 ++++++-
 src/doc/rustc/src/platform-support/android.md |  5 +++++
 .../src/compiler-flags/fixed-x18.md           |  7 ++++++-
 .../src/compiler-flags/sanitizer.md           |  4 ++++
 ...arch64-shadow-call-stack-with-fixed-x18.rs | 19 +++++++++++++++++++
 .../shadow-call-stack-without-fixed-x18.rs    | 15 +++++++++++++++
 6 files changed, 55 insertions(+), 2 deletions(-)
 create mode 100644 tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
 create mode 100644 tests/ui/abi/shadow-call-stack-without-fixed-x18.rs

diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index be67baf57f6dc..8cce665677eb9 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1187,7 +1187,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
 
     // Sanitizers can only be used on platforms that we know have working sanitizer codegen.
     let supported_sanitizers = sess.target.options.supported_sanitizers;
-    let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
+    let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
+    // Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
+    // we should allow Shadow Call Stack sanitizer.
+    if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == "aarch64" {
+        unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
+    }
     match unsupported_sanitizers.into_iter().count() {
         0 => {}
         1 => {
diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md
index 9ddf00e3a5053..96499b0d80148 100644
--- a/src/doc/rustc/src/platform-support/android.md
+++ b/src/doc/rustc/src/platform-support/android.md
@@ -61,3 +61,8 @@ Currently the `riscv64-linux-android` target requires the following architecture
 * `Zba` (address calculation instructions)
 * `Zbb` (base instructions)
 * `Zbs` (single-bit instructions)
+
+### aarch64-linux-android on Nightly compilers
+
+As soon as `-Zfixed-x18` compiler flag is supplied, the [`ShadowCallStack` sanitizer](https://releases.llvm.org/7.0.1/tools/clang/docs/ShadowCallStack.html)
+instrumentation is also made avaiable by supplying the second compiler flag `-Zsanitizer=shadow-call-stack`.
diff --git a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
index 8c8bff5fa296d..b215bc84fbb71 100644
--- a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
+++ b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
@@ -1,7 +1,7 @@
 # `fixed-x18`
 
 This option prevents the compiler from using the x18 register. It is only
-supported on aarch64.
+supported on `aarch64`.
 
 From the [ABI spec][arm-abi]:
 
@@ -23,6 +23,11 @@ Currently, the `-Zsanitizer=shadow-call-stack` flag is only supported on
 platforms that always treat x18 as a reserved register, and the `-Zfixed-x18`
 flag is not required to use the sanitizer on such platforms. However, the
 sanitizer may be supported on targets where this is not the case in the future.
+One way to do so now on Nightly compilers is to explicitly supply this `-Zfixed-x18`
+flag with `aarch64` targets, so that the sanitizer is available for instrumentation
+on targets like `aarch64-unknown-none`, for instance. However, discretion is still
+required to make sure that the runtime support is in place for this sanitizer
+to be effective.
 
 It is undefined behavior for `-Zsanitizer=shadow-call-stack` code to call into
 code where x18 is a temporary register. On the other hand, when you are *not*
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 72b44e002b4d4..edc63a25ac1be 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -787,6 +787,10 @@ A runtime must be provided by the application or operating system.
 
 See the [Clang ShadowCallStack documentation][clang-scs] for more details.
 
+* `aarch64-unknown-none`
+
+In addition to support from a runtime by the application or operating system, the `-Zfixed-x18` flag is also mandatory.
+
 # ThreadSanitizer
 
 ThreadSanitizer is a data race detection tool. It is supported on the following
diff --git a/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
new file mode 100644
index 0000000000000..e2e14ab14a801
--- /dev/null
+++ b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
@@ -0,0 +1,19 @@
+//@ revisions: aarch64 android
+//@[aarch64] compile-flags: --target aarch64-unknown-none -Zfixed-x18 -Zsanitizer=shadow-call-stack
+//@[aarch64] needs-llvm-components: aarch64
+//@[android] compile-flags: --target aarch64-linux-android -Zsanitizer=shadow-call-stack
+//@[android] needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+#[no_mangle]
+pub fn foo() {}
+
+// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}}
diff --git a/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
new file mode 100644
index 0000000000000..d758c903087b6
--- /dev/null
+++ b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: --target aarch64-unknown-none -Zsanitizer=shadow-call-stack
+//@ error-pattern: shadow-call-stack sanitizer is not supported for this target
+//@ dont-check-compiler-stderr
+//@ needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {}