[clang] [Clang][AArch64] Command-line options for A-profile's Sign Return Address Hardening (PR #176171)
Victor Campos via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 16 05:07:41 PDT 2026
https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/176171
>From 4f775ae42fbc2729697b32ed5b5310a86f9cbfc4 Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Tue, 13 Jan 2026 20:39:02 +0000
Subject: [PATCH 1/2] [Clang][AArch64] Command-line options for A-profile's
Sign Return Address Hardening
This patch introduces a new command-line option to enable the AArch64
A-profile's Sign Return Address Hardening. It also introduces a new
function attribute with the same naming as the new command-line option.
At the time of this patch, this new option enables the hardening against
the PACMAN attack [1] using a load of the return address [2].
The new option, -mharden-pac-ret, can take one of two values:
- none: disable hardening. (The default if the option is absent)
- load-return-address: enables hardening using the mitigation based on
load of return address.
The corresponding function attribute takes the option and its possible
values using the same naming.
1: https://pacmanattack.com
2: https://developer.arm.com/documentation/101754/0624/armclang-Reference/armclang-Command-line-Options/-mharden-pac-ret
---
.../clang/Basic/DiagnosticDriverKinds.td | 2 +
.../clang/Basic/DiagnosticSemaKinds.td | 5 +++
clang/include/clang/Basic/LangOptions.def | 2 +
clang/include/clang/Basic/LangOptions.h | 12 ++++++
clang/include/clang/Basic/TargetInfo.h | 22 ++++++++++
clang/include/clang/Options/Options.td | 9 ++++
clang/lib/Basic/Targets/AArch64.cpp | 16 +++++++
clang/lib/Basic/Targets/AArch64.h | 2 +
clang/lib/CodeGen/TargetInfo.cpp | 4 ++
clang/lib/CodeGen/Targets/AArch64.cpp | 3 ++
clang/lib/Driver/ToolChains/Clang.cpp | 22 +++++++++-
clang/lib/Sema/SemaDeclAttr.cpp | 18 +++++++-
.../aarch64-sign-return-address-harden.c | 13 ++++++
clang/test/Driver/aarch64-security-options.c | 30 +++++++++++++
clang/test/Driver/arm-security-options.c | 19 ++++++++
.../Frontend/aarch64-harden-pac-ret-err.c | 3 ++
.../aarch64-harden-pac-ret-attr-err-warn.c | 21 +++++++++
clang/test/Sema/aarch64-harden-pac-ret-attr.c | 43 +++++++++++++++++++
18 files changed, 244 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGen/aarch64-sign-return-address-harden.c
create mode 100644 clang/test/Frontend/aarch64-harden-pac-ret-err.c
create mode 100644 clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
create mode 100644 clang/test/Sema/aarch64-harden-pac-ret-attr.c
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index db0f521b73544..d16fbd45f104e 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -544,6 +544,8 @@ def warn_ignoring_verify_debuginfo_preserve_export : Warning<
InGroup<UnusedCommandLineArgument>;
def warn_unsupported_branch_protection: Warning <
"invalid branch protection option '%0' in '%1'">, InGroup<BranchProtection>;
+def warn_harden_pac_ret_requires_pac_ret: Warning<
+ "ignoring '-mharden-pac-ret' as it requires return address signing">, InGroup<UnusedCommandLineArgument>;
def err_sls_hardening_arm_not_supported : Error<
"-mharden-sls is only supported on armv7-a or later">;
def warn_drv_large_data_threshold_invalid_code_model: Warning<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5cbbc7d130c99..fdfe7792441b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3384,6 +3384,11 @@ def err_invalid_branch_protection_spec : Error<
"invalid or misplaced branch protection specification '%0'">;
def warn_unsupported_branch_protection_spec : Warning<
"unsupported branch protection specification '%0'">, InGroup<BranchProtection>;
+def warn_attribute_harden_pac_ret_requires_pac_ret: Warning<
+ "'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' attribute ignored">,
+ InGroup<IgnoredAttributes>;
+def err_invalid_harden_pac_ret_spec : Error<
+ "invalid or misplaced pac-ret hardening specification '%0'">;
def err_attribute_invalid_atomic_argument : Error<
"invalid argument '%0' to atomic attribute; valid options are: "
"'remote_memory', 'fine_grained_memory', 'ignore_denormal_mode' (optionally "
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 8cba1dbaee24e..f3c5613d3dab7 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -454,6 +454,8 @@ ENUM_LANGOPT(SignReturnAddressScope, SignReturnAddressScopeKind, 2, SignReturnAd
"Scope of return address signing")
ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddressKeyKind::AKey, NotCompatible,
"Key used for return address signing")
+ENUM_LANGOPT(SignReturnAddressHardening, SignReturnAddressHardeningKind, 1,
+ SignReturnAddressHardeningKind::None, NotCompatible, "Hardening of return address signing")
LANGOPT(BranchTargetEnforcement, 1, 0, NotCompatible, "Branch-target enforcement enabled")
LANGOPT(BranchProtectionPAuthLR, 1, 0, NotCompatible, "Use PC as a diversifier using PAuthLR NOP instructions.")
LANGOPT(GuardedControlStack, 1, 0, NotCompatible, "Guarded control stack enabled")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index ebd0436fa154b..c0e82b3edd2cb 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -299,6 +299,13 @@ class LangOptionsBase {
BKey
};
+ enum class SignReturnAddressHardeningKind {
+ /// Regular return address signing.
+ None,
+ /// Hardened return address signing with load of return address.
+ LoadReturnAddress
+ };
+
enum class ThreadModelKind {
/// POSIX Threads.
POSIX,
@@ -728,6 +735,11 @@ class LangOptions : public LangOptionsBase {
return getSignReturnAddressScope() == SignReturnAddressScopeKind::All;
}
+ bool hasSignReturnAddressHardening() const {
+ return getSignReturnAddressHardening() !=
+ SignReturnAddressHardeningKind::None;
+ }
+
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
bool hasDefaultVisibilityExportMapping() const {
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 83467b8e93b6a..10779518275b4 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -62,10 +62,12 @@ struct ParsedTargetAttr {
StringRef CPU;
StringRef Tune;
StringRef BranchProtection;
+ StringRef SignReturnAddrHardening;
StringRef Duplicate;
bool operator ==(const ParsedTargetAttr &Other) const {
return Duplicate == Other.Duplicate && CPU == Other.CPU &&
Tune == Other.Tune && BranchProtection == Other.BranchProtection &&
+ SignReturnAddrHardening == Other.SignReturnAddrHardening &&
Features == Other.Features;
}
};
@@ -1471,6 +1473,7 @@ class TargetInfo : public TransferrableTargetInfo,
public:
LangOptions::SignReturnAddressScopeKind SignReturnAddr;
LangOptions::SignReturnAddressKeyKind SignKey;
+ LangOptions::SignReturnAddressHardeningKind SignReturnAddressHardening;
bool BranchTargetEnforcement;
bool BranchProtectionPAuthLR;
bool GuardedControlStack;
@@ -1497,9 +1500,21 @@ class TargetInfo : public TransferrableTargetInfo,
llvm_unreachable("Unexpected SignReturnAddressKeyKind");
}
+ const char *getSignReturnAddressHardeningStr() const {
+ switch (SignReturnAddressHardening) {
+ case LangOptions::SignReturnAddressHardeningKind::None:
+ return "none";
+ case LangOptions::SignReturnAddressHardeningKind::LoadReturnAddress:
+ return "load-return-address";
+ }
+ llvm_unreachable("Unexpected SignReturnAddressHardeningKind");
+ }
+
BranchProtectionInfo()
: SignReturnAddr(LangOptions::SignReturnAddressScopeKind::None),
SignKey(LangOptions::SignReturnAddressKeyKind::AKey),
+ SignReturnAddressHardening(
+ LangOptions::SignReturnAddressHardeningKind::None),
BranchTargetEnforcement(false), BranchProtectionPAuthLR(false),
GuardedControlStack(false) {}
@@ -1513,6 +1528,7 @@ class TargetInfo : public TransferrableTargetInfo,
SignKey = LangOpts.isSignReturnAddressWithAKey()
? LangOptions::SignReturnAddressKeyKind::AKey
: LangOptions::SignReturnAddressKeyKind::BKey;
+ SignReturnAddressHardening = LangOpts.getSignReturnAddressHardening();
BranchTargetEnforcement = LangOpts.BranchTargetEnforcement;
BranchProtectionPAuthLR = LangOpts.BranchProtectionPAuthLR;
GuardedControlStack = LangOpts.GuardedControlStack;
@@ -1535,6 +1551,12 @@ class TargetInfo : public TransferrableTargetInfo,
return false;
}
+ /// Validate the Return Address Signing Hardening specification
+ virtual std::optional<LangOptions::SignReturnAddressHardeningKind>
+ validateSignReturnAddressHardening(StringRef Spec) const {
+ return std::nullopt;
+ }
+
/// Perform initialization based on the user configured
/// set of features (e.g., +sse4).
///
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 2f57a5b13b917..3ac001d05be82 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5521,6 +5521,15 @@ def msign_return_address_EQ : Joined<["-"], "msign-return-address=">,
Visibility<[ClangOption, CC1Option]>,
Group<m_Group>, Values<"none,all,non-leaf">,
HelpText<"Select return address signing scope">;
+
+def mharden_pac_ret_EQ : Joined<["-"], "mharden-pac-ret=">,
+ Visibility<[ClangOption, CC1Option]>,
+ Flags<[TargetSpecific]>, Group<m_Group>,
+ HelpText<"Select the return address signing hardening scheme. <arg> must be: none, load-return-address">,
+ Values<"none,load-return-address">, NormalizedValues<["None", "LoadReturnAddress"]>,
+ NormalizedValuesScope<"LangOptions::SignReturnAddressHardeningKind">,
+ MarshallingInfoEnum<LangOpts<"SignReturnAddressHardening">, "None">;
+
let Flags = [TargetSpecific] in {
def mbranch_protection_EQ : Joined<["-"], "mbranch-protection=">,
Group<m_Group>,
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index fe407e9fc1789..639540fc13d87 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -276,6 +276,17 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
return true;
}
+std::optional<LangOptions::SignReturnAddressHardeningKind>
+AArch64TargetInfo::validateSignReturnAddressHardening(StringRef Spec) const {
+ assert(!Spec.empty() && "Spec must not be empty");
+ return llvm::StringSwitch<
+ std::optional<LangOptions::SignReturnAddressHardeningKind>>(Spec)
+ .Case("load-return-address",
+ LangOptions::SignReturnAddressHardeningKind::LoadReturnAddress)
+ .Case("none", LangOptions::SignReturnAddressHardeningKind::None)
+ .Default(std::nullopt);
+}
+
bool AArch64TargetInfo::isValidCPUName(StringRef Name) const {
return llvm::AArch64::parseCpu(Name).has_value();
}
@@ -1290,6 +1301,11 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
continue;
}
+ if (Feature.starts_with("harden-pac-ret=")) {
+ Ret.SignReturnAddrHardening = Feature.split('=').second.trim();
+ continue;
+ }
+
if (Feature.starts_with("arch=")) {
if (FoundArch)
Ret.Duplicate = "arch=";
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 2d3b8d2a8d950..c0e52319ba628 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -147,6 +147,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
BranchProtectionInfo &BPI,
const LangOptions &LO,
StringRef &Err) const override;
+ std::optional<LangOptions::SignReturnAddressHardeningKind>
+ validateSignReturnAddressHardening(StringRef Spec) const override;
bool isValidCPUName(StringRef Name) const override;
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 342a3af0ac1ee..530304f9530ad 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -233,6 +233,10 @@ void TargetCodeGenInfo::setBranchProtectionFnAttributes(
if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());
+ if (BPI.SignReturnAddressHardening !=
+ LangOptions::SignReturnAddressHardeningKind::None)
+ F.addFnAttr("sign-return-address-harden",
+ BPI.getSignReturnAddressHardeningStr());
} else {
if (F.hasFnAttribute("sign-return-address"))
F.removeFnAttr("sign-return-address");
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 963b74927036a..2d197e27dc115 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -160,6 +160,9 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
Attr.BranchProtection, Attr.CPU, BPI, CGM.getLangOpts(), Error);
assert(Error.empty());
}
+ if (!Attr.SignReturnAddrHardening.empty())
+ Fn->addFnAttr("sign-return-address-harden",
+ Attr.SignReturnAddrHardening);
}
setBranchProtectionFnAttributes(BPI, *Fn);
setPointerAuthFnAttributes(CGM.getCodeGenOpts().PointerAuth, *Fn);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 4ca98600d6e93..f91e1fd367043 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1378,6 +1378,19 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
? Args.getLastArg(options::OPT_msign_return_address_EQ,
options::OPT_mbranch_protection_EQ)
: Args.getLastArg(options::OPT_mbranch_protection_EQ);
+ const Arg *HardenPACRetArg = Args.getLastArg(options::OPT_mharden_pac_ret_EQ);
+ const Driver &D = TC.getDriver();
+
+ if (HardenPACRetArg) {
+ if (!isAArch64) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << HardenPACRetArg->getSpelling() << TC.getTriple().str();
+ return;
+ }
+ if (!A)
+ D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
+ }
+
if (!A) {
if (Triple.isOSOpenBSD() && isAArch64) {
CmdArgs.push_back("-msign-return-address=non-leaf");
@@ -1387,7 +1400,6 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
return;
}
- const Driver &D = TC.getDriver();
if (!(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass())))
D.Diag(diag::warn_incompatible_branch_protection_option)
<< Triple.getArchName();
@@ -1466,6 +1478,14 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
if (GuardedControlStack)
CmdArgs.push_back("-mguarded-control-stack");
+
+ if (HardenPACRetArg) {
+ if (Scope == "none")
+ D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
+ else
+ CmdArgs.push_back(Args.MakeArgString(Twine("-mharden-pac-ret=") +
+ HardenPACRetArg->getValue()));
+ }
}
void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index d762bcd789bf5..a514be7fd217f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3428,8 +3428,11 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
TargetInfo::BranchProtectionInfo BPI{};
StringRef DiagMsg;
- if (ParsedAttrs.BranchProtection.empty())
+ if (ParsedAttrs.BranchProtection.empty()) {
+ if (!ParsedAttrs.SignReturnAddrHardening.empty())
+ Diag(LiteralLoc, diag::warn_attribute_harden_pac_ret_requires_pac_ret);
return false;
+ }
if (!Context.getTargetInfo().validateBranchProtection(
ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI,
Context.getLangOpts(), DiagMsg)) {
@@ -3442,6 +3445,19 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
if (!DiagMsg.empty())
Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg;
+ if (!ParsedAttrs.SignReturnAddrHardening.empty()) {
+ auto SignReturnAddrOption =
+ Context.getTargetInfo().validateSignReturnAddressHardening(
+ ParsedAttrs.SignReturnAddrHardening);
+ if (!SignReturnAddrOption)
+ return Diag(LiteralLoc, diag::err_invalid_harden_pac_ret_spec)
+ << ParsedAttrs.SignReturnAddrHardening;
+
+ if (BPI.SignReturnAddr == LangOptions::SignReturnAddressScopeKind::None)
+ return Diag(LiteralLoc,
+ diag::warn_attribute_harden_pac_ret_requires_pac_ret);
+ }
+
return false;
}
diff --git a/clang/test/CodeGen/aarch64-sign-return-address-harden.c b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
new file mode 100644
index 0000000000000..6d4db64c5efde
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
@@ -0,0 +1,13 @@
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=none \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=pac-ret \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=pac-ret -mharden-pac-ret=none \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=pac-ret -mharden-pac-ret=load-return-address \
+// RUN: | FileCheck %s --check-prefixes=CHECK-HARDEN
+
+void foo() {}
+
+// CHECK-NO-HARDEN-NOT: attributes #0 = {{.*}}"sign-return-address-harden"
+// CHECK-HARDEN: attributes #0 = {{.*}}"sign-return-address-harden"="load-return-address"
\ No newline at end of file
diff --git a/clang/test/Driver/aarch64-security-options.c b/clang/test/Driver/aarch64-security-options.c
index 146add2d1cf70..fbcf3d75071c6 100644
--- a/clang/test/Driver/aarch64-security-options.c
+++ b/clang/test/Driver/aarch64-security-options.c
@@ -32,6 +32,36 @@
// WARN-NOT: warning: ignoring '-mbranch-protection=' option because the 'aarch64' architecture does not support it [-Wbranch-protection]
+// RUN: %clang -target aarch64 -c %s -### -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=none -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=none -mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=pac-ret -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=pac-ret -mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard -mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
+
+// NO-RA-HARDEN: ignoring '-mharden-pac-ret' as it requires return address signing
+// NO-RA-HARDEN-NOT: "-mharden-pac-ret"
+// NO-RA-HARDEN-LRA: ignoring '-mharden-pac-ret' as it requires return address signing
+// RA-HARDEN-NONE: "-mharden-pac-ret=none"
+// RA-HARDEN-LRA: "-mharden-pac-ret=load-return-address"
+
// RA-OFF: "-msign-return-address=none"
// RA-NON-LEAF: "-msign-return-address=non-leaf"
// RA-ALL: "-msign-return-address=all"
diff --git a/clang/test/Driver/arm-security-options.c b/clang/test/Driver/arm-security-options.c
index 613945c24eede..db1888bec52db 100644
--- a/clang/test/Driver/arm-security-options.c
+++ b/clang/test/Driver/arm-security-options.c
@@ -75,6 +75,23 @@
// RUN: %clang -target arm-arm-none-eabi -march=armv7-r -c %s -### -mbranch-protection=bti 2>&1 | \
// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8m.main -c %s -### -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+bti -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+leaf -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -msign-return-address=all -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -msign-return-address=non-leaf -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+
// RA-OFF: "-msign-return-address=none"
// RA-NON-LEAF: "-msign-return-address=non-leaf"
// RA-ALL: "-msign-return-address=all"
@@ -91,3 +108,5 @@
// BAD-LEAF-COMBINATION: unsupported argument 'leaf' to option '-mbranch-protection='
// INCOMPATIBLE-ARCH: '-mbranch-protection=' option is incompatible with the '{{.*}}' architecture
+
+// RA-HARDEN-INCOMPATIBLE-ARCH: unsupported option '-mharden-pac-ret=' for target 'arm-arm-none-eabi'
diff --git a/clang/test/Frontend/aarch64-harden-pac-ret-err.c b/clang/test/Frontend/aarch64-harden-pac-ret-err.c
new file mode 100644
index 0000000000000..9fc2cba7e8205
--- /dev/null
+++ b/clang/test/Frontend/aarch64-harden-pac-ret-err.c
@@ -0,0 +1,3 @@
+// RUN: not %clang_cc1 -fsyntax-only -triple aarch64 %s -mharden-pac-ret=foo 2>&1 | FileCheck %s
+
+// CHECK: invalid value 'foo' in '-mharden-pac-ret=foo'
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
new file mode 100644
index 0000000000000..3e218253137d6
--- /dev/null
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple aarch64 -verify -fsyntax-only %s
+
+__attribute__((target("harden-pac-ret=none"))) // expected-warning {{'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue0(void) {}
+
+__attribute__((target("harden-pac-ret=load-return-address"))) // expected-warning {{'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue1(void) {}
+
+__attribute__((target("branch-protection=bti,harden-pac-ret=none"))) // expected-warning {{'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue2(void) {}
+
+__attribute__((target("branch-protection=bti,harden-pac-ret=load-return-address"))) // expected-warning {{'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue3(void) {}
+
+__attribute__((target("branch-protection=bti,harden-pac-ret=inexistent"))) // expected-error {{invalid or misplaced pac-ret hardening specification 'inexistent'}}
+void
+badvalue4(void) {}
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr.c b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
new file mode 100644
index 0000000000000..c05e33ee28055
--- /dev/null
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK
+
+__attribute__ ((target("branch-protection=pac-ret,harden-pac-ret=none")))
+void f1() {}
+// CHECK: define{{.*}} void @f1() #[[#F1:]]
+
+__attribute__ ((target("branch-protection=pac-ret,harden-pac-ret=load-return-address")))
+void f2() {}
+// CHECK: define{{.*}} void @f2() #[[#F2:]]
+
+__attribute__ ((target("branch-protection=pac-ret+leaf,harden-pac-ret=none")))
+void f3() {}
+// CHECK: define{{.*}} void @f3() #[[#F3:]]
+
+__attribute__ ((target("branch-protection=pac-ret+leaf,harden-pac-ret=load-return-address")))
+void f4() {}
+// CHECK: define{{.*}} void @f4() #[[#F4:]]
+
+__attribute__ ((target("branch-protection=pac-ret+b-key,harden-pac-ret=none")))
+void f5() {}
+// CHECK: define{{.*}} void @f5() #[[#F5:]]
+
+__attribute__ ((target("branch-protection=pac-ret+b-key,harden-pac-ret=load-return-address")))
+void f6() {}
+// CHECK: define{{.*}} void @f6() #[[#F6:]]
+
+__attribute__ ((target("branch-protection=pac-ret+leaf+b-key,harden-pac-ret=none")))
+void f7() {}
+// CHECK: define{{.*}} void @f7() #[[#F7:]]
+
+__attribute__ ((target("branch-protection=pac-ret+leaf+b-key,harden-pac-ret=load-return-address")))
+void f8() {}
+// CHECK: define{{.*}} void @f8() #[[#F8:]]
+
+// CHECK-DAG: attributes #[[#F1]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="none"
+// CHECK-DAG: attributes #[[#F2]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="load-return-address"
+// CHECK-DAG: attributes #[[#F3]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="none"
+// CHECK-DAG: attributes #[[#F4]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="load-return-address"
+// CHECK-DAG: attributes #[[#F5]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="none" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#F6]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="load-return-address" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#F7]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="none" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#F8]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="load-return-address" "sign-return-address-key"="b_key"
>From 97c8d752b6115d3a2e7d6e4c84c35ea0baa641bc Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Mon, 13 Apr 2026 11:39:18 +0100
Subject: [PATCH 2/2] Address code reviews
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/include/clang/Basic/LangOptions.h | 5 -
clang/include/clang/Basic/TargetInfo.h | 4 +-
clang/lib/Basic/Targets/AArch64.cpp | 3 +-
clang/lib/Basic/Targets/AArch64.h | 2 +-
clang/lib/CodeGen/TargetInfo.cpp | 13 ++
clang/lib/CodeGen/Targets/AArch64.cpp | 13 +-
clang/lib/Driver/ToolChains/Clang.cpp | 127 +++++++++---------
clang/lib/Sema/SemaDeclAttr.cpp | 12 +-
.../aarch64-sign-return-address-harden.c | 8 ++
clang/test/Driver/aarch64-security-options.c | 17 ++-
.../aarch64-harden-pac-ret-attr-err-warn.c | 2 +-
clang/test/Sema/aarch64-harden-pac-ret-attr.c | 31 +++--
13 files changed, 144 insertions(+), 95 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdfe7792441b9..e963eb7d1399b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3388,7 +3388,7 @@ def warn_attribute_harden_pac_ret_requires_pac_ret: Warning<
"'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' attribute ignored">,
InGroup<IgnoredAttributes>;
def err_invalid_harden_pac_ret_spec : Error<
- "invalid or misplaced pac-ret hardening specification '%0'">;
+ "invalid or misspelled pac-ret hardening specification '%0'">;
def err_attribute_invalid_atomic_argument : Error<
"invalid argument '%0' to atomic attribute; valid options are: "
"'remote_memory', 'fine_grained_memory', 'ignore_denormal_mode' (optionally "
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index c0e82b3edd2cb..bc7deae9c5122 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -735,11 +735,6 @@ class LangOptions : public LangOptionsBase {
return getSignReturnAddressScope() == SignReturnAddressScopeKind::All;
}
- bool hasSignReturnAddressHardening() const {
- return getSignReturnAddressHardening() !=
- SignReturnAddressHardeningKind::None;
- }
-
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
bool hasDefaultVisibilityExportMapping() const {
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 10779518275b4..7d64a9d7bd4bb 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1551,9 +1551,9 @@ class TargetInfo : public TransferrableTargetInfo,
return false;
}
- /// Validate the Return Address Signing Hardening specification
+ /// Parse the Return Address Signing Hardening specification.
virtual std::optional<LangOptions::SignReturnAddressHardeningKind>
- validateSignReturnAddressHardening(StringRef Spec) const {
+ parseSignReturnAddressHardening(StringRef Spec) const {
return std::nullopt;
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 639540fc13d87..da10cd384b963 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -277,8 +277,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
}
std::optional<LangOptions::SignReturnAddressHardeningKind>
-AArch64TargetInfo::validateSignReturnAddressHardening(StringRef Spec) const {
- assert(!Spec.empty() && "Spec must not be empty");
+AArch64TargetInfo::parseSignReturnAddressHardening(StringRef Spec) const {
return llvm::StringSwitch<
std::optional<LangOptions::SignReturnAddressHardeningKind>>(Spec)
.Case("load-return-address",
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index c0e52319ba628..9312b785dd20b 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -148,7 +148,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
const LangOptions &LO,
StringRef &Err) const override;
std::optional<LangOptions::SignReturnAddressHardeningKind>
- validateSignReturnAddressHardening(StringRef Spec) const override;
+ parseSignReturnAddressHardening(StringRef Spec) const override;
bool isValidCPUName(StringRef Name) const override;
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 530304f9530ad..9e0b7bb709cc9 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -230,6 +230,7 @@ void TargetCodeGenInfo::setBranchProtectionFnAttributes(
// Called on already created and initialized function where attributes already
// set from command line attributes but some might need to be removed as the
// actual BPI is different.
+
if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());
@@ -244,6 +245,14 @@ void TargetCodeGenInfo::setBranchProtectionFnAttributes(
F.removeFnAttr("sign-return-address-key");
}
+ if (BPI.SignReturnAddressHardening ==
+ LangOptions::SignReturnAddressHardeningKind::None) {
+ F.removeFnAttr("sign-return-address-harden");
+ } else {
+ F.addFnAttr("sign-return-address-harden",
+ BPI.getSignReturnAddressHardeningStr());
+ }
+
auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) {
if (Set)
F.addFnAttr(ModAttr);
@@ -266,6 +275,10 @@ void TargetCodeGenInfo::initBranchProtectionFnAttributes(
FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr());
FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr());
}
+ if (BPI.SignReturnAddressHardening !=
+ LangOptions::SignReturnAddressHardeningKind::None)
+ FuncAttrs.addAttribute("sign-return-address-harden",
+ BPI.getSignReturnAddressHardeningStr());
if (BPI.BranchTargetEnforcement)
FuncAttrs.addAttribute("branch-target-enforcement");
if (BPI.BranchProtectionPAuthLR)
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 2d197e27dc115..87219df5cbc83 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -159,10 +159,17 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
(void)CGM.getTarget().validateBranchProtection(
Attr.BranchProtection, Attr.CPU, BPI, CGM.getLangOpts(), Error);
assert(Error.empty());
+
+ // Hardening is only accepted in the target attribute if PAC-RET is also
+ // present there. Invalid combinations are handled in Sema.
+ if (BPI.SignReturnAddr !=
+ LangOptions::SignReturnAddressScopeKind::None) {
+ if (auto Hardening = CGM.getTarget().parseSignReturnAddressHardening(
+ Attr.SignReturnAddrHardening)) {
+ BPI.SignReturnAddressHardening = *Hardening;
+ }
+ }
}
- if (!Attr.SignReturnAddrHardening.empty())
- Fn->addFnAttr("sign-return-address-harden",
- Attr.SignReturnAddrHardening);
}
setBranchProtectionFnAttributes(BPI, *Fn);
setPointerAuthFnAttributes(CGM.getCodeGenOpts().PointerAuth, *Fn);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index f91e1fd367043..ed200b6ec3ec9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1381,79 +1381,85 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
const Arg *HardenPACRetArg = Args.getLastArg(options::OPT_mharden_pac_ret_EQ);
const Driver &D = TC.getDriver();
+ // Check CmdArgs because some toolchains bypass the driver args and add to
+ // the frontend args directly.
+ bool HasPtrauthReturns = llvm::is_contained(CmdArgs, "-fptrauth-returns") ||
+ Args.hasArgNoClaim(options::OPT_fno_ptrauth_returns,
+ options::OPT_fptrauth_returns);
+
if (HardenPACRetArg) {
if (!isAArch64) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< HardenPACRetArg->getSpelling() << TC.getTriple().str();
return;
}
- if (!A)
- D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
+ StringRef ArgValue = HardenPACRetArg->getValue();
+ if (ArgValue != "none" && ArgValue != "load-return-address") {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << HardenPACRetArg->getSpelling() << ArgValue;
+ return;
+ }
}
- if (!A) {
- if (Triple.isOSOpenBSD() && isAArch64) {
- CmdArgs.push_back("-msign-return-address=non-leaf");
- CmdArgs.push_back("-msign-return-address-key=a_key");
- CmdArgs.push_back("-mbranch-target-enforce");
- }
+ if (!A && Triple.isOSOpenBSD() && isAArch64) {
+ CmdArgs.push_back("-msign-return-address=non-leaf");
+ CmdArgs.push_back("-msign-return-address-key=a_key");
+ CmdArgs.push_back("-mbranch-target-enforce");
return;
}
- if (!(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass())))
+ if (A && !(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass())))
D.Diag(diag::warn_incompatible_branch_protection_option)
<< Triple.getArchName();
- StringRef Scope, Key;
- bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack;
-
- if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
- Scope = A->getValue();
- if (Scope != "none" && Scope != "non-leaf" && Scope != "all")
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getSpelling() << Scope;
- Key = "a_key";
- IndirectBranches = Triple.isOSOpenBSD() && isAArch64;
- BranchProtectionPAuthLR = false;
- GuardedControlStack = false;
- } else {
- StringRef DiagMsg;
- llvm::ARM::ParsedBranchProtection PBP;
- bool EnablePAuthLR = false;
-
- // To know if we need to enable PAuth-LR As part of the standard branch
- // protection option, it needs to be determined if the feature has been
- // activated in the `march` argument. This information is stored within the
- // CmdArgs variable and can be found using a search.
- if (isAArch64) {
- auto isPAuthLR = [](const char *member) {
- llvm::AArch64::ExtensionInfo pauthlr_extension =
- llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR);
- return pauthlr_extension.PosTargetFeature == member;
- };
+ StringRef Scope = "none", Key;
+ bool IndirectBranches = false, BranchProtectionPAuthLR = false,
+ GuardedControlStack = false;
- if (llvm::any_of(CmdArgs, isPAuthLR))
- EnablePAuthLR = true;
+ if (A) {
+ if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
+ Scope = A->getValue();
+ if (Scope != "none" && Scope != "non-leaf" && Scope != "all")
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Scope;
+ Key = "a_key";
+ IndirectBranches = Triple.isOSOpenBSD() && isAArch64;
+ BranchProtectionPAuthLR = false;
+ GuardedControlStack = false;
+ } else {
+ StringRef DiagMsg;
+ llvm::ARM::ParsedBranchProtection PBP;
+ bool EnablePAuthLR = false;
+
+ // To know if we need to enable PAuth-LR As part of the standard branch
+ // protection option, it needs to be determined if the feature has been
+ // activated in the `march` argument. This information is stored within
+ // the CmdArgs variable and can be found using a search.
+ if (isAArch64) {
+ auto isPAuthLR = [](const char *member) {
+ llvm::AArch64::ExtensionInfo pauthlr_extension =
+ llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR);
+ return pauthlr_extension.PosTargetFeature == member;
+ };
+
+ if (llvm::any_of(CmdArgs, isPAuthLR))
+ EnablePAuthLR = true;
+ }
+ if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg,
+ EnablePAuthLR))
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << DiagMsg;
+ if (!isAArch64 && PBP.Key == "b_key")
+ D.Diag(diag::warn_unsupported_branch_protection)
+ << "b-key" << A->getAsString(Args);
+ Scope = PBP.Scope;
+ Key = PBP.Key;
+ BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
+ IndirectBranches = PBP.BranchTargetEnforcement;
+ GuardedControlStack = PBP.GuardedControlStack;
}
- if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg,
- EnablePAuthLR))
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getSpelling() << DiagMsg;
- if (!isAArch64 && PBP.Key == "b_key")
- D.Diag(diag::warn_unsupported_branch_protection)
- << "b-key" << A->getAsString(Args);
- Scope = PBP.Scope;
- Key = PBP.Key;
- BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
- IndirectBranches = PBP.BranchTargetEnforcement;
- GuardedControlStack = PBP.GuardedControlStack;
- }
-
- Arg *PtrauthReturnsArg = Args.getLastArg(options::OPT_fptrauth_returns,
- options::OPT_fno_ptrauth_returns);
- bool HasPtrauthReturns =
- PtrauthReturnsArg &&
- PtrauthReturnsArg->getOption().matches(options::OPT_fptrauth_returns);
+ }
+
// GCS is currently untested with ptrauth-returns, but enabling this could be
// allowed in future after testing with a suitable system.
if (Scope != "none" || BranchProtectionPAuthLR || GuardedControlStack) {
@@ -1465,8 +1471,9 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< A->getAsString(Args) << "-fptrauth-returns";
}
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-msign-return-address=") + Scope));
+ if (A)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-msign-return-address=") + Scope));
if (Scope != "none")
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
@@ -1480,7 +1487,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-mguarded-control-stack");
if (HardenPACRetArg) {
- if (Scope == "none")
+ if (Scope == "none" && !HasPtrauthReturns)
D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
else
CmdArgs.push_back(Args.MakeArgString(Twine("-mharden-pac-ret=") +
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index a514be7fd217f..9118f7bef778e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3426,13 +3426,15 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
<< Unsupported << None << CurFeature << Target;
}
- TargetInfo::BranchProtectionInfo BPI{};
- StringRef DiagMsg;
if (ParsedAttrs.BranchProtection.empty()) {
if (!ParsedAttrs.SignReturnAddrHardening.empty())
Diag(LiteralLoc, diag::warn_attribute_harden_pac_ret_requires_pac_ret);
return false;
}
+
+ TargetInfo::BranchProtectionInfo BPI{};
+ StringRef DiagMsg;
+
if (!Context.getTargetInfo().validateBranchProtection(
ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI,
Context.getLangOpts(), DiagMsg)) {
@@ -3446,10 +3448,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg;
if (!ParsedAttrs.SignReturnAddrHardening.empty()) {
- auto SignReturnAddrOption =
- Context.getTargetInfo().validateSignReturnAddressHardening(
+ auto SignReturnAddrHardenOpt =
+ Context.getTargetInfo().parseSignReturnAddressHardening(
ParsedAttrs.SignReturnAddrHardening);
- if (!SignReturnAddrOption)
+ if (!SignReturnAddrHardenOpt)
return Diag(LiteralLoc, diag::err_invalid_harden_pac_ret_spec)
<< ParsedAttrs.SignReturnAddrHardening;
diff --git a/clang/test/CodeGen/aarch64-sign-return-address-harden.c b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
index 6d4db64c5efde..4b078bbc367b3 100644
--- a/clang/test/CodeGen/aarch64-sign-return-address-harden.c
+++ b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
@@ -1,11 +1,19 @@
// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=none \
// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s -fno-ptrauth-returns \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=pac-ret \
// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s -fptrauth-returns \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=pac-ret -mharden-pac-ret=none \
// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s -fptrauth-returns -mharden-pac-ret=none \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=pac-ret -mharden-pac-ret=load-return-address \
// RUN: | FileCheck %s --check-prefixes=CHECK-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s -fptrauth-returns -mharden-pac-ret=load-return-address \
+// RUN: | FileCheck %s --check-prefixes=CHECK-HARDEN
void foo() {}
diff --git a/clang/test/Driver/aarch64-security-options.c b/clang/test/Driver/aarch64-security-options.c
index fbcf3d75071c6..321205abd8e1a 100644
--- a/clang/test/Driver/aarch64-security-options.c
+++ b/clang/test/Driver/aarch64-security-options.c
@@ -32,6 +32,9 @@
// WARN-NOT: warning: ignoring '-mbranch-protection=' option because the 'aarch64' architecture does not support it [-Wbranch-protection]
+// RUN: %clang -target aarch64 -c %s -### 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=ABSENT-RA-HARDEN
+
// RUN: %clang -target aarch64 -c %s -### -mharden-pac-ret=none 2>&1 | \
// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
@@ -56,11 +59,15 @@
// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard -mharden-pac-ret=load-return-address 2>&1 | \
// RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
-// NO-RA-HARDEN: ignoring '-mharden-pac-ret' as it requires return address signing
-// NO-RA-HARDEN-NOT: "-mharden-pac-ret"
-// NO-RA-HARDEN-LRA: ignoring '-mharden-pac-ret' as it requires return address signing
-// RA-HARDEN-NONE: "-mharden-pac-ret=none"
-// RA-HARDEN-LRA: "-mharden-pac-ret=load-return-address"
+// RUN: not %clang -target aarch64 -c %s -### -mbranch-protection=standard -mharden-pac-ret=foo 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=BAD-HARDEN-PROTECTION
+
+// ABSENT-RA-HARDEN-NOT: "-mharden-pac-ret"
+// NO-RA-HARDEN: ignoring '-mharden-pac-ret' as it requires return address signing
+// NO-RA-HARDEN-NOT: "-mharden-pac-ret"
+// RA-HARDEN-NONE: "-mharden-pac-ret=none"
+// RA-HARDEN-LRA: "-mharden-pac-ret=load-return-address"
+// BAD-HARDEN-PROTECTION: unsupported argument 'foo' to option '-mharden-pac-ret='
// RA-OFF: "-msign-return-address=none"
// RA-NON-LEAF: "-msign-return-address=non-leaf"
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
index 3e218253137d6..a98a80c85c819 100644
--- a/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
@@ -16,6 +16,6 @@ __attribute__((target("branch-protection=bti,harden-pac-ret=load-return-address"
void
badvalue3(void) {}
-__attribute__((target("branch-protection=bti,harden-pac-ret=inexistent"))) // expected-error {{invalid or misplaced pac-ret hardening specification 'inexistent'}}
+__attribute__((target("branch-protection=bti,harden-pac-ret=inexistent"))) // expected-error {{invalid or misspelled pac-ret hardening specification 'inexistent'}}
void
badvalue4(void) {}
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr.c b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
index c05e33ee28055..28795003e3a5b 100644
--- a/clang/test/Sema/aarch64-harden-pac-ret-attr.c
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - \
-// RUN: | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - | FileCheck %s
+
+// The following test that the function attributes take precedence over command-line options
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic -target-feature +v8.5a %s -msign-return-address=all -mharden-pac-ret=none -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic -target-feature +v8.5a %s -msign-return-address=all -mharden-pac-ret=load-return-address -o - | FileCheck %s
__attribute__ ((target("branch-protection=pac-ret,harden-pac-ret=none")))
void f1() {}
@@ -33,11 +36,19 @@ __attribute__ ((target("branch-protection=pac-ret+leaf+b-key,harden-pac-ret=load
void f8() {}
// CHECK: define{{.*}} void @f8() #[[#F8:]]
-// CHECK-DAG: attributes #[[#F1]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="none"
-// CHECK-DAG: attributes #[[#F2]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="load-return-address"
-// CHECK-DAG: attributes #[[#F3]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="none"
-// CHECK-DAG: attributes #[[#F4]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="load-return-address"
-// CHECK-DAG: attributes #[[#F5]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="none" "sign-return-address-key"="b_key"
-// CHECK-DAG: attributes #[[#F6]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="load-return-address" "sign-return-address-key"="b_key"
-// CHECK-DAG: attributes #[[#F7]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="none" "sign-return-address-key"="b_key"
-// CHECK-DAG: attributes #[[#F8]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="load-return-address" "sign-return-address-key"="b_key"
+// These check patterns rely on the fact that "sign-return-address-harden" appears after "sign-return-address"
+
+// CHECK: attributes #[[#F1]] = { {{.*}} "sign-return-address"="non-leaf"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK: attributes #[[#F2]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="load-return-address"
+// CHECK: attributes #[[#F3]] = { {{.*}} "sign-return-address"="all"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK: attributes #[[#F4]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="load-return-address"
+// CHECK: attributes #[[#F5]] = { {{.*}} "sign-return-address"="non-leaf"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK: "sign-return-address-key"="b_key"
+// CHECK: attributes #[[#F6]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-harden"="load-return-address" "sign-return-address-key"="b_key"
+// CHECK: attributes #[[#F7]] = { {{.*}} "sign-return-address"="all"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK: "sign-return-address-key"="b_key"
+// CHECK: attributes #[[#F8]] = { {{.*}} "sign-return-address"="all" "sign-return-address-harden"="load-return-address" "sign-return-address-key"="b_key"
More information about the cfe-commits
mailing list