[clang] 9a1ebae - [AARCH64] Support TPIDR_EL0 and TPIDRRO_EL0 as stack protector sysregs (#188054)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 25 08:57:18 PDT 2026


Author: Ard Biesheuvel
Date: 2026-03-25T08:57:12-07:00
New Revision: 9a1ebae0296b544a3b5a5f2bbaee8e8803427de9

URL: https://github.com/llvm/llvm-project/commit/9a1ebae0296b544a3b5a5f2bbaee8e8803427de9
DIFF: https://github.com/llvm/llvm-project/commit/9a1ebae0296b544a3b5a5f2bbaee8e8803427de9.diff

LOG: [AARCH64] Support TPIDR_EL0 and TPIDRRO_EL0 as stack protector sysregs (#188054)

Even though the command line option suggests that arbitrary system
registers may be chosen, the sysreg option for the stack protector guard
currently only permits SP_EL0, as this is what the Linux kernel uses.

While it makes no sense to permit arbitrary system registers here (which
usually have side effects), there is a desire to switch to TPIDR_EL0 or
TPIDRRO_EL0 from the Linux side, both of which are part of the base v8.0
AArch64 ISA, and can hold arbitrary 64-bit values without side effects.

So add TPIDR_EL0 and TPIDRRO_EL0 to the set of accepted arguments for
the -mstack-protected-guard-reg= command line option. For good measure,
add TPIDR_EL1, TPIDR_EL2, FAR_EL1 and FAR_EL2 as well, all of which
could potentially be useful to privileged software such as the Linux
kernel to stash a per-thread pointer to the stack protector guard value.

Signed-off-by: Ard Biesheuvel <ardb at kernel.org>

Added: 
    

Modified: 
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/test/CodeGen/stack-protector-guard.c
    clang/test/Driver/stack-protector-guard.c
    llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll

Removed: 
    


################################################################################
diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6416baf9126ff..d2dcc8a800766 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3588,8 +3588,15 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
           << A->getOption().getName() << Value << "fs gs";
       return;
     }
-    if (EffectiveTriple.isAArch64() && Value != "sp_el0") {
-      D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value;
+    if (EffectiveTriple.isAArch64() &&
+        llvm::StringSwitch<bool>(Value)
+            .Cases({"sp_el0", "tpidrro_el0", "tpidr_el0", "tpidr_el1",
+                    "tpidr_el2", "far_el1", "far_el2"},
+                   false)
+            .Default(true)) {
+      D.Diag(diag::err_drv_invalid_value_with_suggestion)
+          << A->getOption().getName() << Value
+          << "{sp_el0, tpidrro_el0, tpidr_el[012], far_el[12]}";
       return;
     }
     if (EffectiveTriple.isRISCV() && Value != "tp") {

diff  --git a/clang/test/CodeGen/stack-protector-guard.c b/clang/test/CodeGen/stack-protector-guard.c
index 0a4da13eed95c..7bffa2a1107a4 100644
--- a/clang/test/CodeGen/stack-protector-guard.c
+++ b/clang/test/CodeGen/stack-protector-guard.c
@@ -8,7 +8,25 @@
 // RUN:   -mstack-protector-guard-offset=1024 -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
 // RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=sp_el0 \
-// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-SP
+// RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
+// RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=tpidrro_el0 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-TPIDRRO
+// RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
+// RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=tpidr_el0 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-TPIDR-EL0
+// RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
+// RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=tpidr_el1 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-TPIDR-EL1
+// RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
+// RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=tpidr_el2 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-TPIDR-EL2
+// RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
+// RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=far_el1 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-FAR-EL1
+// RUN: %clang_cc1 -mstack-protector-guard=sysreg -triple aarch64-linux-gnu \
+// RUN:   -mstack-protector-guard-offset=1024 -mstack-protector-guard-reg=far_el2 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=AARCH64 --check-prefix=AARCH64-FAR-EL2
 // RUN: %clang_cc1 -mstack-protector-guard=tls -triple riscv64-unknown-elf \
 // RUN:   -mstack-protector-guard-offset=44 -mstack-protector-guard-reg=tp \
 // RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefix=RISCV
@@ -30,7 +48,13 @@ void bar(int x) {
 
 // AARCH64: !llvm.module.flags = !{{{.*}}[[ATTR1:![0-9]+]], [[ATTR2:![0-9]+]], [[ATTR3:![0-9]+]]}
 // AARCH64: [[ATTR1]] = !{i32 1, !"stack-protector-guard", !"sysreg"}
-// AARCH64: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"sp_el0"}
+// AARCH64-SP: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"sp_el0"}
+// AARCH64-TPIDRRO: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"tpidrro_el0"}
+// AARCH64-TPIDR-EL0: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"tpidr_el0"}
+// AARCH64-TPIDR-EL1: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"tpidr_el1"}
+// AARCH64-TPIDR-EL2: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"tpidr_el2"}
+// AARCH64-FAR-EL1: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"far_el1"}
+// AARCH64-FAR-EL2: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"far_el2"}
 // AARCH64: [[ATTR3]] = !{i32 1, !"stack-protector-guard-offset", i32 1024}
 
 // RISCV: !llvm.module.flags = !{{{.*}}[[ATTR1:![0-9]+]], [[ATTR2:![0-9]+]], [[ATTR3:![0-9]+]], [[ATTR4:![0-9]+]]}

diff  --git a/clang/test/Driver/stack-protector-guard.c b/clang/test/Driver/stack-protector-guard.c
index 666c83079e519..a31eeefa36ddd 100644
--- a/clang/test/Driver/stack-protector-guard.c
+++ b/clang/test/Driver/stack-protector-guard.c
@@ -81,10 +81,15 @@
 // RUN:   -mstack-protector-guard-reg=foo \
 // RUN:   -mstack-protector-guard-offset=0 %s 2>&1 | \
 // RUN: FileCheck -check-prefix=INVALID-REG-AARCH64 %s
+// RUN: %clang -### -target aarch64-linux-gnu -mstack-protector-guard=sysreg \
+// RUN:   -mstack-protector-guard-reg=tpidr_el0 \
+// RUN:   -mstack-protector-guard-offset=0 %s 2>&1 | \
+// RUN: FileCheck -check-prefix=CHECK-AARCH64-TPIDR %s
 
 // CHECK-AARCH64: "-cc1" {{.*}}"-mstack-protector-guard=sysreg" "-mstack-protector-guard-offset=0" "-mstack-protector-guard-reg=sp_el0"
 // INVALID-VALUE-AARCH64: error: invalid value 'tls' in 'mstack-protector-guard=', expected one of: sysreg global
-// INVALID-REG-AARCH64: error: invalid value 'foo' in 'mstack-protector-guard-reg='
+// INVALID-REG-AARCH64: error: invalid value 'foo' in 'mstack-protector-guard-reg=', expected one of: {sp_el0, tpidrro_el0, tpidr_el[012], far_el[12]}
+// CHECK-AARCH64-TPIDR: "-cc1" {{.*}}"-mstack-protector-guard=sysreg" "-mstack-protector-guard-offset=0" "-mstack-protector-guard-reg=tpidr_el0"
 
 // RUN: %clang -### -target riscv64-unknown-elf -mstack-protector-guard=tls -mstack-protector-guard-offset=24 -mstack-protector-guard-reg=tp %s 2>&1 | \
 // RUN:   FileCheck -v -check-prefix=CHECK-TLS-RISCV %s

diff  --git a/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll b/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll
index 60e8823934d15..44bd696640113 100644
--- a/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll
+++ b/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll
@@ -10,19 +10,19 @@
 ; RUN: cat %t/main.ll %t/i.ll > %t/i2.ll
 ; RUN: cat %t/main.ll %t/j.ll > %t/j2.ll
 ; RUN: llc %t/a2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NO-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-SP --check-prefix=CHECK-NO-OFFSET %s
 ; RUN: llc %t/b2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-POSITIVE-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-TPIDRRO --check-prefix=CHECK-POSITIVE-OFFSET %s
 ; RUN: llc %t/c2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NEGATIVE-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-TPIDR0 --check-prefix=CHECK-NEGATIVE-OFFSET %s
 ; RUN: llc %t/d2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NPOT-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-TPIDR1 --check-prefix=CHECK-NPOT-OFFSET %s
 ; RUN: llc %t/e2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NPOT-NEG-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-TPIDR2 --check-prefix=CHECK-NPOT-NEG-OFFSET %s
 ; RUN: llc %t/f2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK-ADD --check-prefix=CHECK-257-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK-ADD --check-prefix=CHECK-FAR1 --check-prefix=CHECK-257-OFFSET %s
 ; RUN: llc %t/g2.ll -verify-machineinstrs -o - | \
-; RUN: FileCheck --check-prefix=CHECK-ADD --check-prefix=CHECK-MINUS-257-OFFSET %s
+; RUN: FileCheck --check-prefix=CHECK-ADD --check-prefix=CHECK-FAR2 --check-prefix=CHECK-MINUS-257-OFFSET %s
 
 ; XFAIL
 ; RUN: not --crash llc %t/h2.ll -o - 2>&1 | \
@@ -50,7 +50,11 @@ define dso_local void @foo(i64 %t) local_unnamed_addr #0 {
 ; CHECK-NEXT:    .cfi_offset w29, -16
 ; CHECK-NEXT:    .cfi_remember_state
 ; CHECK-NEXT:    sub     sp, sp, #16
-; CHECK-NEXT:    mrs     x8, SP_EL0
+; CHECK-SP:      mrs     x8, SP_EL0
+; CHECK-TPIDRRO: mrs     x8, TPIDRRO_EL0
+; CHECK-TPIDR0:  mrs     x8, TPIDR_EL0
+; CHECK-TPIDR1:  mrs     x8, TPIDR_EL1
+; CHECK-TPIDR2:  mrs     x8, TPIDR_EL2
 ; CHECK-NEXT:    lsl     x9, x0, #2
 ; CHECK-NO-OFFSET: ldr     x8, [x8]
 ; CHECK-POSITIVE-OFFSET: ldr x8, [x8, #8]
@@ -64,7 +68,11 @@ define dso_local void @foo(i64 %t) local_unnamed_addr #0 {
 ; CHECK-NEXT     sub     x0, x8, x9
 ; CHECK-NEXT     mov     sp, x0
 ; CHECK-NEXT     bl      baz
-; CHECK-NEXT     mrs     x8, SP_EL0
+; CHECK-SP:      mrs     x8, SP_EL0
+; CHECK-TPIDRRO: mrs     x8, TPIDRRO_EL0
+; CHECK-TPIDR0:  mrs     x8, TPIDR_EL0
+; CHECK-TPIDR1:  mrs     x8, TPIDR_EL1
+; CHECK-TPIDR2:  mrs     x8, TPIDR_EL2
 ; CHECK-NO-OFFSET:       ldr x8, [x8]
 ; CHECK-POSITIVE-OFFSET: ldr x8, [x8, #8]
 ; CHECK-NEGATIVE-OFFSET: ldur x8, [x8, #-8]
@@ -99,7 +107,8 @@ define dso_local void @foo(i64 %t) local_unnamed_addr #0 {
 ; CHECK-ADD-NEXT:        .cfi_offset w29, -16
 ; CHECK-ADD-NEXT:        .cfi_remember_state
 ; CHECK-ADD-NEXT:        sub     sp, sp, #16
-; CHECK-ADD-NEXT:        mrs     x8, SP_EL0
+; CHECK-FAR1:            mrs     x8, FAR_EL1
+; CHECK-FAR2:            mrs     x8, FAR_EL2
 ; CHECK-ADD-NEXT:        lsl     x9, x0, #2
 ; CHECK-MINUS-257-OFFSET: sub     x8, x8, #257
 ; CHECK-257-OFFSET:      add     x8, x8, #257
@@ -111,7 +120,8 @@ define dso_local void @foo(i64 %t) local_unnamed_addr #0 {
 ; CHECK-ADD-NEXT:        sub     x0, x8, x9
 ; CHECK-ADD-NEXT:        mov     sp, x0
 ; CHECK-ADD-NEXT:        bl      baz
-; CHECK-ADD-NEXT:        mrs     x8, SP_EL0
+; CHECK-FAR1:            mrs     x8, FAR_EL1
+; CHECK-FAR2:            mrs     x8, FAR_EL2
 ; CHECK-257-OFFSET:      add     x8, x8, #257
 ; CHECK-MINUS-257-OFFSET: sub     x8, x8, #257
 ; CHECK-ADD-NEXT:         ldr     x8, [x8]
@@ -148,25 +158,34 @@ attributes #0 = { sspstrong uwtable }
 !llvm.module.flags = !{!1, !2, !3}
 
 !1 = !{i32 2, !"stack-protector-guard", !"sysreg"}
-!2 = !{i32 2, !"stack-protector-guard-reg", !"sp_el0"}
 
 ;--- a.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"sp_el0"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 0}
 ;--- b.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"tpidrro_el0"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 8}
 ;--- c.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"tpidr_el0"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 -8}
 ;--- d.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"tpidr_el1"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 1}
 ;--- e.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"tpidr_el2"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 -1}
 ;--- f.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"far_el1"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 257}
 ;--- g.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"far_el2"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 -257}
 ;--- h.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"sp_el0"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 32761}
 ;--- i.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"sp_el0"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 -4096}
 ;--- j.ll
+!2 = !{i32 2, !"stack-protector-guard-reg", !"sp_el0"}
 !3 = !{i32 2, !"stack-protector-guard-offset", i32 4097}


        


More information about the cfe-commits mailing list