[llvm] [AArch64] Fix the emission of WinCFI for pac-ret+leaf and SCS (PR #147518)
Anatoly Trosinenko via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 8 06:18:05 PDT 2025
https://github.com/atrosinenko created https://github.com/llvm/llvm-project/pull/147518
This commit fixes WinCFI opcodes being incorrectly emitted for test cases in sign-return-address.ll.
Emit SEH_Nop opcode in emitShadowCallStackEpilogue the same way it is done in emitShadowCallStackPrologue function - this fixes
12 bytes of instructions in range, but .seh directives corresponding to 8 bytes
error being reported for the epilogue of non_leaf_scs function.
Emit SEH_PrologEnd on the code path in emitPrologue function that may be taken when pac-ret protection is emitted for a leaf function - this fixes errors like the following:
starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue) in leaf_sign_all_v83
Stray .seh_endepilogue in leaf_sign_all_v83
>From ef5d3b9fdf4b852e9df28062eeb278c77f04dfa3 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Tue, 8 Jul 2025 14:51:42 +0300
Subject: [PATCH] [AArch64] Fix the emission of WinCFI for pac-ret+leaf and SCS
This commit fixes WinCFI opcodes being incorrectly emitted for test
cases in sign-return-address.ll.
Emit SEH_Nop opcode in emitShadowCallStackEpilogue the same way it
is done in emitShadowCallStackPrologue function - this fixes
12 bytes of instructions in range, but .seh directives corresponding to 8 bytes
error being reported for the epilogue of non_leaf_scs function.
Emit SEH_PrologEnd on the code path in emitPrologue function that may be
taken when pac-ret protection is emitted for a leaf function - this
fixes errors like the following:
starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue) in leaf_sign_all_v83
Stray .seh_endepilogue in leaf_sign_all_v83
---
.../Target/AArch64/AArch64FrameLowering.cpp | 32 +++++++++++++------
.../CodeGen/AArch64/sign-return-address.ll | 5 +++
2 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 6f1ce5bdbe286..aa4b13d3829d4 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -1673,7 +1673,7 @@ static void emitShadowCallStackEpilogue(const TargetInstrInfo &TII,
MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL) {
+ const DebugLoc &DL, bool NeedsWinCFI) {
// Shadow call stack epilog: ldr x30, [x18, #-8]!
BuildMI(MBB, MBBI, DL, TII.get(AArch64::LDRXpre))
.addReg(AArch64::X18, RegState::Define)
@@ -1682,6 +1682,10 @@ static void emitShadowCallStackEpilogue(const TargetInstrInfo &TII,
.addImm(-8)
.setMIFlag(MachineInstr::FrameDestroy);
+ if (NeedsWinCFI)
+ BuildMI(MBB, MBBI, DL, TII.get(AArch64::SEH_Nop))
+ .setMIFlag(MachineInstr::FrameDestroy);
+
if (MF.getInfo<AArch64FunctionInfo>()->needsAsyncDwarfUnwindInfo(MF))
CFIInstBuilder(MBB, MBBI, MachineInstr::FrameDestroy)
.buildRestore(AArch64::X18);
@@ -1786,15 +1790,17 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
DebugLoc DL;
const auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
- if (MFnI.needsShadowCallStackPrologueEpilogue(MF))
+ if (MFnI.needsShadowCallStackPrologueEpilogue(MF)) {
emitShadowCallStackPrologue(*TII, MF, MBB, MBBI, DL, NeedsWinCFI,
MFnI.needsDwarfUnwindInfo(MF));
+ HasWinCFI |= NeedsWinCFI;
+ }
if (MFnI.shouldSignReturnAddress(MF)) {
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_PROLOGUE))
.setMIFlag(MachineInstr::FrameSetup);
- if (NeedsWinCFI)
- HasWinCFI = true; // AArch64PointerAuth pass will insert SEH_PACSignLR
+ // AArch64PointerAuth pass will insert SEH_PACSignLR
+ HasWinCFI |= NeedsWinCFI;
}
if (EmitCFI && MFnI.isMTETagged()) {
@@ -1880,8 +1886,13 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
"unexpected function without stack frame but with SVE objects");
// All of the stack allocation is for locals.
AFI->setLocalStackSize(NumBytes);
- if (!NumBytes)
+ if (!NumBytes) {
+ if (NeedsWinCFI && HasWinCFI) {
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
return;
+ }
// REDZONE: If the stack size is less than 128 bytes, we don't need
// to actually allocate.
if (canUseRedZone(MF)) {
@@ -2354,11 +2365,14 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
BuildMI(MBB, MBB.getFirstTerminator(), DL,
TII->get(AArch64::PAUTH_EPILOGUE))
.setMIFlag(MachineInstr::FrameDestroy);
- if (NeedsWinCFI)
- HasWinCFI = true; // AArch64PointerAuth pass will insert SEH_PACSignLR
+ // AArch64PointerAuth pass will insert SEH_PACSignLR
+ HasWinCFI |= NeedsWinCFI;
+ }
+ if (AFI->needsShadowCallStackPrologueEpilogue(MF)) {
+ emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL,
+ NeedsWinCFI);
+ HasWinCFI |= NeedsWinCFI;
}
- if (AFI->needsShadowCallStackPrologueEpilogue(MF))
- emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL);
if (EmitCFI)
emitCalleeSavedGPRRestores(MBB, MBB.getFirstTerminator());
if (HasWinCFI) {
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address.ll b/llvm/test/CodeGen/AArch64/sign-return-address.ll
index dafe0d71ceb5f..67c58f6d12eb5 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address.ll
@@ -5,6 +5,11 @@
; v9.5-A is not expected to change codegen without -mbranch-protection=+pc, so reuse V83A.
; RUN: llc -mtriple=aarch64 -mattr=v9.5a < %s | FileCheck --check-prefixes=CHECK,V83A %s
+; Make sure no errors are detected when emitting SEH opcodes.
+; Errors are only checked for when generating a binary, so emit a dummy object
+; file and make sure llc produces zero exit code.
+; RUN: llc -mtriple=aarch64-windows -o %t.dummy.o --filetype=obj < %s
+
define i32 @leaf(i32 %x) {
; CHECK-LABEL: leaf:
; CHECK: // %bb.0:
More information about the llvm-commits
mailing list