[llvm] [AArch64][PAC] Protect the entire function if pac-ret+leaf is passed (PR #140895)
Anatoly Trosinenko via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 2 07:00:24 PDT 2025
https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/140895
>From 494d1e6699fa8d67446c8c9f40c48978aaec3f0d Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Tue, 20 May 2025 20:46:43 +0300
Subject: [PATCH 1/5] [AArch64][PAC] Protect the entire function if
pac-ret+leaf is passed
Normally, pac-ret hardening is emitted as part of function prologues and
epilogues, thus it is affected by the shrink-wrapping optimization.
As protecting LR when it is spilled to the stack is already handled by
regular -mbranch-protection=pac-ret option, it is reasonable to assume
that pac-ret+leaf option means the user wants to apply pac-ret hardening
to as much code as possible. For that reason, if pac-ret+leaf hardening
mode is requested, this patch moves the emission of PAUTH_PROLOGUE (or
PAUTH_EPILOGUE) pseudos from emitPrologue (emitEpilogue) methods of the
AArch64FrameLowering class to processFunctionBeforeFrameIndicesReplaced.
This commit only affects where LR is signed and authenticated, but does
not otherwise prevents the shrink-wrapping optimization. Moreover,
without "+leaf" modifier PAUTH_(PROLOGUE|EPILOGUE) pseudos respect the
shrink-wrapping optimization just as any other prologue/epilogue code.
---
.../Target/AArch64/AArch64FrameLowering.cpp | 60 +++++++++++--
.../lib/Target/AArch64/AArch64FrameLowering.h | 8 ++
.../AArch64/AArch64MachineFunctionInfo.cpp | 4 +
.../AArch64/AArch64MachineFunctionInfo.h | 1 +
...sign-return-address-cfi-negate-ra-state.ll | 6 +-
.../AArch64/sign-return-address-tailcall.ll | 2 +-
.../CodeGen/AArch64/sign-return-address.ll | 86 +++++++++++++++++++
7 files changed, 158 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 6f1ce5bdbe286..a27365cd1ffbd 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -1717,6 +1717,39 @@ static void getLivePhysRegsUpTo(MachineInstr &MI, const TargetRegisterInfo &TRI,
}
#endif
+void AArch64FrameLowering::emitPacRetPlusLeafHardening(
+ MachineFunction &MF) const {
+ const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+
+ auto EmitSignRA = [&](MachineBasicBlock &MBB) {
+ DebugLoc DL; // Set debug location to unknown.
+ MachineBasicBlock::iterator MBBI = MBB.begin();
+
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_PROLOGUE))
+ .setMIFlag(MachineInstr::FrameSetup);
+ };
+
+ auto EmitAuthRA = [&](MachineBasicBlock &MBB) {
+ DebugLoc DL;
+ MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
+ if (MBBI != MBB.end())
+ DL = MBBI->getDebugLoc();
+
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_EPILOGUE))
+ .setMIFlag(MachineInstr::FrameDestroy);
+ };
+
+ // This should be in sync with PEIImpl::calculateSaveRestoreBlocks.
+ EmitSignRA(MF.front());
+ for (MachineBasicBlock &MBB : MF) {
+ if (MBB.isEHFuncletEntry())
+ EmitSignRA(MBB);
+ if (MBB.isReturnBlock())
+ EmitAuthRA(MBB);
+ }
+}
+
void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
@@ -1791,8 +1824,12 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
MFnI.needsDwarfUnwindInfo(MF));
if (MFnI.shouldSignReturnAddress(MF)) {
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_PROLOGUE))
- .setMIFlag(MachineInstr::FrameSetup);
+ // If pac-ret+leaf is in effect, PAUTH_PROLOGUE pseudo instructions
+ // are inserted by emitPacRetPlusLeafHardening().
+ if (!MFnI.shouldSignReturnAddressEverywhere()) {
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_PROLOGUE))
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
if (NeedsWinCFI)
HasWinCFI = true; // AArch64PointerAuth pass will insert SEH_PACSignLR
}
@@ -2351,9 +2388,13 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
auto FinishingTouches = make_scope_exit([&]() {
if (AFI->shouldSignReturnAddress(MF)) {
- BuildMI(MBB, MBB.getFirstTerminator(), DL,
- TII->get(AArch64::PAUTH_EPILOGUE))
- .setMIFlag(MachineInstr::FrameDestroy);
+ // If pac-ret+leaf is in effect, PAUTH_EPILOGUE pseudo instructions
+ // are inserted by emitPacRetPlusLeafHardening().
+ if (!AFI->shouldSignReturnAddressEverywhere()) {
+ BuildMI(MBB, MBB.getFirstTerminator(), DL,
+ TII->get(AArch64::PAUTH_EPILOGUE))
+ .setMIFlag(MachineInstr::FrameDestroy);
+ }
if (NeedsWinCFI)
HasWinCFI = true; // AArch64PointerAuth pass will insert SEH_PACSignLR
}
@@ -5143,6 +5184,8 @@ static void emitVGSaveRestore(MachineBasicBlock::iterator II,
void AArch64FrameLowering::processFunctionBeforeFrameIndicesReplaced(
MachineFunction &MF, RegScavenger *RS = nullptr) const {
+ AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
+
for (auto &BB : MF)
for (MachineBasicBlock::iterator II = BB.begin(); II != BB.end();) {
if (requiresSaveVG(MF))
@@ -5150,6 +5193,13 @@ void AArch64FrameLowering::processFunctionBeforeFrameIndicesReplaced(
else if (StackTaggingMergeSetTag)
II = tryMergeAdjacentSTG(II, this, RS);
}
+
+ // By the time this method is called, most of the prologue/epilogue code is
+ // already emitted, whether its location was affected by the shrink-wrapping
+ // optimization or not.
+ if (!MF.getFunction().hasFnAttribute(Attribute::Naked) &&
+ AFI->shouldSignReturnAddressEverywhere())
+ emitPacRetPlusLeafHardening(MF);
}
/// For Win64 AArch64 EH, the offset to the Unwind object is from the SP
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index e7d52bb350f13..dd44588ab8b26 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -36,6 +36,14 @@ class AArch64FrameLowering : public TargetFrameLowering {
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+ /// Harden the entire function with pac-ret.
+ ///
+ /// If pac-ret+leaf is requested, we want to harden as much code as possible.
+ /// This function inserts pac-ret hardening at the points where prologue and
+ /// epilogue are traditionally inserted, ignoring possible shrink-wrapping
+ /// optimization.
+ void emitPacRetPlusLeafHardening(MachineFunction &MF) const;
+
bool enableCFIFixup(const MachineFunction &MF) const override;
bool enableFullCFIFixup(const MachineFunction &MF) const override;
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 4b04b80121ffa..f3c1ea6c18ddb 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -162,6 +162,10 @@ bool AArch64FunctionInfo::shouldSignReturnAddress(
return shouldSignReturnAddress(isLRSpilled(MF));
}
+bool AArch64FunctionInfo::shouldSignReturnAddressEverywhere() const {
+ return SignReturnAddressAll;
+}
+
bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue(
MachineFunction &MF) const {
if (!(isLRSpilled(MF) &&
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index e61f2280865b4..5b084dbbba168 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -543,6 +543,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
bool shouldSignReturnAddress(const MachineFunction &MF) const;
bool shouldSignReturnAddress(bool SpillsLR) const;
+ bool shouldSignReturnAddressEverywhere() const;
bool needsShadowCallStackPrologueEpilogue(MachineFunction &MF) const;
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll b/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
index 4d4b7c215b978..bf70bf30534ec 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
@@ -74,9 +74,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V8A-NEXT: bl _Z3bari
; CHECK-V8A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V8A-NEXT: .cfi_def_cfa_offset 0
+; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: hint #29
; CHECK-V8A-NEXT: .cfi_negate_ra_state
-; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: b _Z3bari
; CHECK-V8A-NEXT: .LBB1_2: // %if.else
; CHECK-V8A-NEXT: .cfi_restore_state
@@ -84,9 +84,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V8A-NEXT: add w0, w0, #1
; CHECK-V8A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V8A-NEXT: .cfi_def_cfa_offset 0
+; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: hint #29
; CHECK-V8A-NEXT: .cfi_negate_ra_state
-; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: ret
;
; CHECK-V83A-LABEL: baz_async:
@@ -103,9 +103,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V83A-NEXT: bl _Z3bari
; CHECK-V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V83A-NEXT: .cfi_def_cfa_offset 0
+; CHECK-V83A-NEXT: .cfi_restore w30
; CHECK-V83A-NEXT: autiasp
; CHECK-V83A-NEXT: .cfi_negate_ra_state
-; CHECK-V83A-NEXT: .cfi_restore w30
; CHECK-V83A-NEXT: b _Z3bari
; CHECK-V83A-NEXT: .LBB1_2: // %if.else
; CHECK-V83A-NEXT: .cfi_restore_state
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll b/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll
index 032d3cc05961f..90e48fe0ed042 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll
@@ -156,8 +156,8 @@ define i32 @tailcall_two_branches(i1 %0) "sign-return-address"="all" {
; COMMON: str x30, [sp, #-16]!
; COMMON: bl callee2
; COMMON: ldr x30, [sp], #16
-; COMMON-NEXT: [[AUTIASP]]
; COMMON-NEXT: .[[ELSE]]:
+; COMMON-NEXT: [[AUTIASP]]
; LDR-NEXT: ldr w16, [x30]
;
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address.ll b/llvm/test/CodeGen/AArch64/sign-return-address.ll
index dafe0d71ceb5f..61b72d806e082 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address.ll
@@ -149,6 +149,92 @@ define i32 @non_leaf_scs(i32 %x) "sign-return-address"="non-leaf" shadowcallstac
ret i32 %call
}
+; By default, pac-ret hardening respects shrink-wrapping optimization.
+define void @shrink_wrap_sign_non_leaf(i32 %x, i32 %cond) "sign-return-address"="non-leaf" {
+; COMPAT-LABEL: shrink_wrap_sign_non_leaf:
+; COMPAT: // %bb.0: // %entry
+; COMPAT-NEXT: cbz w1, .LBB8_2
+; COMPAT-NEXT: // %bb.1: // %common.ret
+; COMPAT-NEXT: ret
+; COMPAT-NEXT: .LBB8_2: // %if.then
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; COMPAT-NEXT: .cfi_def_cfa_offset 16
+; COMPAT-NEXT: .cfi_offset w30, -16
+; COMPAT-NEXT: bl foo
+; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: shrink_wrap_sign_non_leaf:
+; V83A: // %bb.0: // %entry
+; V83A-NEXT: cbz w1, .LBB8_2
+; V83A-NEXT: // %bb.1: // %common.ret
+; V83A-NEXT: ret
+; V83A-NEXT: .LBB8_2: // %if.then
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; V83A-NEXT: .cfi_def_cfa_offset 16
+; V83A-NEXT: .cfi_offset w30, -16
+; V83A-NEXT: bl foo
+; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: retaa
+entry:
+ %cond.bool = icmp eq i32 %cond, 0
+ br i1 %cond.bool, label %if.then, label %if.else
+if.then:
+ %call = call i32 @foo(i32 %x)
+ ret void
+if.else:
+ ret void
+}
+
+; When "+leaf" is specified to harden everything, pac-ret hardens the entire
+; function, ignoring shrink-wrapping.
+define void @shrink_wrap_sign_all(i32 %x, i32 %cond) "sign-return-address"="all" {
+; COMPAT-LABEL: shrink_wrap_sign_all:
+; COMPAT: // %bb.0: // %entry
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: cbz w1, .LBB9_2
+; COMPAT-NEXT: // %bb.1: // %common.ret
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+; COMPAT-NEXT: .LBB9_2: // %if.then
+; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; COMPAT-NEXT: .cfi_def_cfa_offset 16
+; COMPAT-NEXT: .cfi_offset w30, -16
+; COMPAT-NEXT: bl foo
+; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: shrink_wrap_sign_all:
+; V83A: // %bb.0: // %entry
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: cbz w1, .LBB9_2
+; V83A-NEXT: // %bb.1: // %common.ret
+; V83A-NEXT: retaa
+; V83A-NEXT: .LBB9_2: // %if.then
+; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; V83A-NEXT: .cfi_def_cfa_offset 16
+; V83A-NEXT: .cfi_offset w30, -16
+; V83A-NEXT: bl foo
+; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: retaa
+entry:
+ %cond.bool = icmp eq i32 %cond, 0
+ br i1 %cond.bool, label %if.then, label %if.else
+if.then:
+ %call = call i32 @foo(i32 %x)
+ ret void
+if.else:
+ ret void
+}
+
define i32 @leaf_sign_all_v83(i32 %x) "sign-return-address"="all" "target-features"="+v8.3a" {
; CHECK-LABEL: leaf_sign_all_v83:
; CHECK: // %bb.0:
>From 991a501ecf52f9de5cb70e801d27ca7f5af05b23 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 4 Jun 2025 23:07:52 +0300
Subject: [PATCH 2/5] Emit .cfi_restore after PAUTH_EPILOGUE
---
.../Target/AArch64/AArch64FrameLowering.cpp | 18 ++++++++++++++++++
.../sign-return-address-cfi-negate-ra-state.ll | 6 +++---
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index a27365cd1ffbd..a8d7f48ec6618 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -711,7 +711,14 @@ static void emitCalleeSavedRestores(MachineBasicBlock &MBB,
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameDestroy);
+ // If pac-ret+leaf is in effect, ".cfi_restore w30" is emitted near
+ // PAUTH_EPILOGUE pseudo instruction by emitPacRetPlusLeafHardening().
+ bool ShouldSkipLR = MF.getInfo<AArch64FunctionInfo>()->shouldSignReturnAddressEverywhere();
+
for (const auto &Info : CSI) {
+ if (ShouldSkipLR && Info.getReg() == AArch64::LR)
+ continue;
+
if (SVE !=
(MFI.getStackID(Info.getFrameIdx()) == TargetStackID::ScalableVector))
continue;
@@ -1721,6 +1728,12 @@ void AArch64FrameLowering::emitPacRetPlusLeafHardening(
MachineFunction &MF) const {
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
+
+ bool SpillsLR = llvm::any_of(
+ MF.getFrameInfo().getCalleeSavedInfo(),
+ [](const auto &Info) { return Info.getReg() == AArch64::LR; });
+ bool EmitCFI = AFI->needsAsyncDwarfUnwindInfo(MF);
auto EmitSignRA = [&](MachineBasicBlock &MBB) {
DebugLoc DL; // Set debug location to unknown.
@@ -1738,6 +1751,11 @@ void AArch64FrameLowering::emitPacRetPlusLeafHardening(
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_EPILOGUE))
.setMIFlag(MachineInstr::FrameDestroy);
+
+ if (EmitCFI && SpillsLR) {
+ CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameDestroy);
+ CFIBuilder.buildRestore(AArch64::LR);
+ }
};
// This should be in sync with PEIImpl::calculateSaveRestoreBlocks.
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll b/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
index bf70bf30534ec..4d4b7c215b978 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
@@ -74,9 +74,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V8A-NEXT: bl _Z3bari
; CHECK-V8A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V8A-NEXT: .cfi_def_cfa_offset 0
-; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: hint #29
; CHECK-V8A-NEXT: .cfi_negate_ra_state
+; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: b _Z3bari
; CHECK-V8A-NEXT: .LBB1_2: // %if.else
; CHECK-V8A-NEXT: .cfi_restore_state
@@ -84,9 +84,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V8A-NEXT: add w0, w0, #1
; CHECK-V8A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V8A-NEXT: .cfi_def_cfa_offset 0
-; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: hint #29
; CHECK-V8A-NEXT: .cfi_negate_ra_state
+; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: ret
;
; CHECK-V83A-LABEL: baz_async:
@@ -103,9 +103,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V83A-NEXT: bl _Z3bari
; CHECK-V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V83A-NEXT: .cfi_def_cfa_offset 0
-; CHECK-V83A-NEXT: .cfi_restore w30
; CHECK-V83A-NEXT: autiasp
; CHECK-V83A-NEXT: .cfi_negate_ra_state
+; CHECK-V83A-NEXT: .cfi_restore w30
; CHECK-V83A-NEXT: b _Z3bari
; CHECK-V83A-NEXT: .LBB1_2: // %if.else
; CHECK-V83A-NEXT: .cfi_restore_state
>From 06d9d39bf830d713c81735d9b1f12910fe1ee818 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 4 Jun 2025 23:26:06 +0300
Subject: [PATCH 3/5] Fix formatting
---
llvm/lib/Target/AArch64/AArch64FrameLowering.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index a8d7f48ec6618..5a027207ee591 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -713,7 +713,8 @@ static void emitCalleeSavedRestores(MachineBasicBlock &MBB,
// If pac-ret+leaf is in effect, ".cfi_restore w30" is emitted near
// PAUTH_EPILOGUE pseudo instruction by emitPacRetPlusLeafHardening().
- bool ShouldSkipLR = MF.getInfo<AArch64FunctionInfo>()->shouldSignReturnAddressEverywhere();
+ bool ShouldSkipLR =
+ MF.getInfo<AArch64FunctionInfo>()->shouldSignReturnAddressEverywhere();
for (const auto &Info : CSI) {
if (ShouldSkipLR && Info.getReg() == AArch64::LR)
>From 4bc4eaa9f7bbc75badfd2a366f589d487612cfee Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 2 Jul 2025 16:06:54 +0300
Subject: [PATCH 4/5] Improve test cases
---
.../CodeGen/AArch64/sign-return-address.ll | 75 ++++++++++++-------
1 file changed, 49 insertions(+), 26 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address.ll b/llvm/test/CodeGen/AArch64/sign-return-address.ll
index 61b72d806e082..15154d6e3336c 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address.ll
@@ -149,14 +149,14 @@ define i32 @non_leaf_scs(i32 %x) "sign-return-address"="non-leaf" shadowcallstac
ret i32 %call
}
+ at var = dso_local global i64 0
+
; By default, pac-ret hardening respects shrink-wrapping optimization.
-define void @shrink_wrap_sign_non_leaf(i32 %x, i32 %cond) "sign-return-address"="non-leaf" {
+define void @shrink_wrap_sign_non_leaf(i32 %x, i32 %cond) "sign-return-address"="non-leaf" uwtable(async) {
; COMPAT-LABEL: shrink_wrap_sign_non_leaf:
; COMPAT: // %bb.0: // %entry
-; COMPAT-NEXT: cbz w1, .LBB8_2
-; COMPAT-NEXT: // %bb.1: // %common.ret
-; COMPAT-NEXT: ret
-; COMPAT-NEXT: .LBB8_2: // %if.then
+; COMPAT-NEXT: cbnz w1, .LBB8_2
+; COMPAT-NEXT: // %bb.1: // %if.then
; COMPAT-NEXT: hint #25
; COMPAT-NEXT: .cfi_negate_ra_state
; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
@@ -164,15 +164,20 @@ define void @shrink_wrap_sign_non_leaf(i32 %x, i32 %cond) "sign-return-address"=
; COMPAT-NEXT: .cfi_offset w30, -16
; COMPAT-NEXT: bl foo
; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: .cfi_def_cfa_offset 0
; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: .cfi_restore w30
+; COMPAT-NEXT: .LBB8_2: // %exit
+; COMPAT-NEXT: adrp x8, var
+; COMPAT-NEXT: mov w9, #42 // =0x2a
+; COMPAT-NEXT: str x9, [x8, :lo12:var]
; COMPAT-NEXT: ret
;
; V83A-LABEL: shrink_wrap_sign_non_leaf:
; V83A: // %bb.0: // %entry
-; V83A-NEXT: cbz w1, .LBB8_2
-; V83A-NEXT: // %bb.1: // %common.ret
-; V83A-NEXT: ret
-; V83A-NEXT: .LBB8_2: // %if.then
+; V83A-NEXT: cbnz w1, .LBB8_2
+; V83A-NEXT: // %bb.1: // %if.then
; V83A-NEXT: paciasp
; V83A-NEXT: .cfi_negate_ra_state
; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
@@ -180,58 +185,76 @@ define void @shrink_wrap_sign_non_leaf(i32 %x, i32 %cond) "sign-return-address"=
; V83A-NEXT: .cfi_offset w30, -16
; V83A-NEXT: bl foo
; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
-; V83A-NEXT: retaa
+; V83A-NEXT: .cfi_def_cfa_offset 0
+; V83A-NEXT: autiasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: .cfi_restore w30
+; V83A-NEXT: .LBB8_2: // %exit
+; V83A-NEXT: adrp x8, var
+; V83A-NEXT: mov w9, #42 // =0x2a
+; V83A-NEXT: str x9, [x8, :lo12:var]
+; V83A-NEXT: ret
entry:
%cond.bool = icmp eq i32 %cond, 0
- br i1 %cond.bool, label %if.then, label %if.else
+ br i1 %cond.bool, label %if.then, label %exit
if.then:
%call = call i32 @foo(i32 %x)
- ret void
-if.else:
+ br label %exit
+exit:
+ store i64 42, ptr @var
ret void
}
; When "+leaf" is specified to harden everything, pac-ret hardens the entire
; function, ignoring shrink-wrapping.
-define void @shrink_wrap_sign_all(i32 %x, i32 %cond) "sign-return-address"="all" {
+define void @shrink_wrap_sign_all(i32 %x, i32 %cond) "sign-return-address"="all" uwtable(async) {
; COMPAT-LABEL: shrink_wrap_sign_all:
; COMPAT: // %bb.0: // %entry
; COMPAT-NEXT: hint #25
; COMPAT-NEXT: .cfi_negate_ra_state
-; COMPAT-NEXT: cbz w1, .LBB9_2
-; COMPAT-NEXT: // %bb.1: // %common.ret
-; COMPAT-NEXT: hint #29
-; COMPAT-NEXT: ret
-; COMPAT-NEXT: .LBB9_2: // %if.then
+; COMPAT-NEXT: cbnz w1, .LBB9_2
+; COMPAT-NEXT: // %bb.1: // %if.then
; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
; COMPAT-NEXT: .cfi_def_cfa_offset 16
; COMPAT-NEXT: .cfi_offset w30, -16
; COMPAT-NEXT: bl foo
; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: .cfi_def_cfa_offset 0
+; COMPAT-NEXT: .LBB9_2: // %exit
+; COMPAT-NEXT: adrp x8, var
+; COMPAT-NEXT: mov w9, #42 // =0x2a
+; COMPAT-NEXT: str x9, [x8, :lo12:var]
; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: .cfi_restore w30
; COMPAT-NEXT: ret
;
; V83A-LABEL: shrink_wrap_sign_all:
; V83A: // %bb.0: // %entry
; V83A-NEXT: paciasp
; V83A-NEXT: .cfi_negate_ra_state
-; V83A-NEXT: cbz w1, .LBB9_2
-; V83A-NEXT: // %bb.1: // %common.ret
-; V83A-NEXT: retaa
-; V83A-NEXT: .LBB9_2: // %if.then
+; V83A-NEXT: cbnz w1, .LBB9_2
+; V83A-NEXT: // %bb.1: // %if.then
; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
; V83A-NEXT: .cfi_def_cfa_offset 16
; V83A-NEXT: .cfi_offset w30, -16
; V83A-NEXT: bl foo
; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: .cfi_def_cfa_offset 0
+; V83A-NEXT: .LBB9_2: // %exit
+; V83A-NEXT: adrp x8, var
+; V83A-NEXT: mov w9, #42 // =0x2a
+; V83A-NEXT: str x9, [x8, :lo12:var]
+; V83A-NEXT: .cfi_restore w30
; V83A-NEXT: retaa
entry:
%cond.bool = icmp eq i32 %cond, 0
- br i1 %cond.bool, label %if.then, label %if.else
+ br i1 %cond.bool, label %if.then, label %exit
if.then:
%call = call i32 @foo(i32 %x)
- ret void
-if.else:
+ br label %exit
+exit:
+ store i64 42, ptr @var
ret void
}
>From e918a8ac14095c50aadaf0e2b35a67672056669f Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 2 Jul 2025 16:12:09 +0300
Subject: [PATCH 5/5] Revert the change to .cfi_restore w30 emission
---
.../Target/AArch64/AArch64FrameLowering.cpp | 19 -------------------
...sign-return-address-cfi-negate-ra-state.ll | 6 +++---
.../CodeGen/AArch64/sign-return-address.ll | 4 ++--
3 files changed, 5 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 5a027207ee591..a27365cd1ffbd 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -711,15 +711,7 @@ static void emitCalleeSavedRestores(MachineBasicBlock &MBB,
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameDestroy);
- // If pac-ret+leaf is in effect, ".cfi_restore w30" is emitted near
- // PAUTH_EPILOGUE pseudo instruction by emitPacRetPlusLeafHardening().
- bool ShouldSkipLR =
- MF.getInfo<AArch64FunctionInfo>()->shouldSignReturnAddressEverywhere();
-
for (const auto &Info : CSI) {
- if (ShouldSkipLR && Info.getReg() == AArch64::LR)
- continue;
-
if (SVE !=
(MFI.getStackID(Info.getFrameIdx()) == TargetStackID::ScalableVector))
continue;
@@ -1729,12 +1721,6 @@ void AArch64FrameLowering::emitPacRetPlusLeafHardening(
MachineFunction &MF) const {
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
- const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
-
- bool SpillsLR = llvm::any_of(
- MF.getFrameInfo().getCalleeSavedInfo(),
- [](const auto &Info) { return Info.getReg() == AArch64::LR; });
- bool EmitCFI = AFI->needsAsyncDwarfUnwindInfo(MF);
auto EmitSignRA = [&](MachineBasicBlock &MBB) {
DebugLoc DL; // Set debug location to unknown.
@@ -1752,11 +1738,6 @@ void AArch64FrameLowering::emitPacRetPlusLeafHardening(
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_EPILOGUE))
.setMIFlag(MachineInstr::FrameDestroy);
-
- if (EmitCFI && SpillsLR) {
- CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameDestroy);
- CFIBuilder.buildRestore(AArch64::LR);
- }
};
// This should be in sync with PEIImpl::calculateSaveRestoreBlocks.
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll b/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
index 4d4b7c215b978..bf70bf30534ec 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-cfi-negate-ra-state.ll
@@ -74,9 +74,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V8A-NEXT: bl _Z3bari
; CHECK-V8A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V8A-NEXT: .cfi_def_cfa_offset 0
+; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: hint #29
; CHECK-V8A-NEXT: .cfi_negate_ra_state
-; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: b _Z3bari
; CHECK-V8A-NEXT: .LBB1_2: // %if.else
; CHECK-V8A-NEXT: .cfi_restore_state
@@ -84,9 +84,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V8A-NEXT: add w0, w0, #1
; CHECK-V8A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V8A-NEXT: .cfi_def_cfa_offset 0
+; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: hint #29
; CHECK-V8A-NEXT: .cfi_negate_ra_state
-; CHECK-V8A-NEXT: .cfi_restore w30
; CHECK-V8A-NEXT: ret
;
; CHECK-V83A-LABEL: baz_async:
@@ -103,9 +103,9 @@ define hidden noundef i32 @baz_async(i32 noundef %a) #0 uwtable(async) {
; CHECK-V83A-NEXT: bl _Z3bari
; CHECK-V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; CHECK-V83A-NEXT: .cfi_def_cfa_offset 0
+; CHECK-V83A-NEXT: .cfi_restore w30
; CHECK-V83A-NEXT: autiasp
; CHECK-V83A-NEXT: .cfi_negate_ra_state
-; CHECK-V83A-NEXT: .cfi_restore w30
; CHECK-V83A-NEXT: b _Z3bari
; CHECK-V83A-NEXT: .LBB1_2: // %if.else
; CHECK-V83A-NEXT: .cfi_restore_state
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address.ll b/llvm/test/CodeGen/AArch64/sign-return-address.ll
index 15154d6e3336c..c79e49ca4539d 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address.ll
@@ -220,13 +220,13 @@ define void @shrink_wrap_sign_all(i32 %x, i32 %cond) "sign-return-address"="all"
; COMPAT-NEXT: bl foo
; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; COMPAT-NEXT: .cfi_def_cfa_offset 0
+; COMPAT-NEXT: .cfi_restore w30
; COMPAT-NEXT: .LBB9_2: // %exit
; COMPAT-NEXT: adrp x8, var
; COMPAT-NEXT: mov w9, #42 // =0x2a
; COMPAT-NEXT: str x9, [x8, :lo12:var]
; COMPAT-NEXT: hint #29
; COMPAT-NEXT: .cfi_negate_ra_state
-; COMPAT-NEXT: .cfi_restore w30
; COMPAT-NEXT: ret
;
; V83A-LABEL: shrink_wrap_sign_all:
@@ -241,11 +241,11 @@ define void @shrink_wrap_sign_all(i32 %x, i32 %cond) "sign-return-address"="all"
; V83A-NEXT: bl foo
; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
; V83A-NEXT: .cfi_def_cfa_offset 0
+; V83A-NEXT: .cfi_restore w30
; V83A-NEXT: .LBB9_2: // %exit
; V83A-NEXT: adrp x8, var
; V83A-NEXT: mov w9, #42 // =0x2a
; V83A-NEXT: str x9, [x8, :lo12:var]
-; V83A-NEXT: .cfi_restore w30
; V83A-NEXT: retaa
entry:
%cond.bool = icmp eq i32 %cond, 0
More information about the llvm-commits
mailing list