diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1661,6 +1661,10 @@ case AArch64::SEH_EpilogEnd: TS->emitARM64WinCFIEpilogEnd(); return; + + case AArch64::SEH_PACSignLR: + TS->emitARM64WinCFIPACSignLR(); + return; } // Finally, do the automated lowerings for everything else. diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -1409,6 +1409,8 @@ if (MFnI.shouldSignWithBKey()) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY)) .setMIFlag(MachineInstr::FrameSetup); + // No SEH opcode for this one; it doesn't materialize into an + // instruction on Windows. PACI = Subtarget.hasPAuth() ? AArch64::PACIB : AArch64::PACIBSP; } else { PACI = Subtarget.hasPAuth() ? AArch64::PACIA : AArch64::PACIASP; @@ -1426,6 +1428,10 @@ BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); + } else if (NeedsWinCFI) { + HasWinCFI = true; + BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR)) + .setMIFlag(MachineInstr::FrameSetup); } } if (EmitCFI && MFnI.isMTETagged()) { @@ -1853,8 +1859,8 @@ } } -static void InsertReturnAddressAuth(MachineFunction &MF, - MachineBasicBlock &MBB) { +static void InsertReturnAddressAuth(MachineFunction &MF, MachineBasicBlock &MBB, + bool NeedsWinCFI, bool *HasWinCFI) { const auto &MFI = *MF.getInfo(); if (!MFI.shouldSignReturnAddress()) return; @@ -1873,7 +1879,8 @@ // DW_CFA_AARCH64_negate_ra_state can't be emitted. if (Subtarget.hasPAuth() && !MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack) && - MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR) { + MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR && + !NeedsWinCFI) { BuildMI(MBB, MBBI, DL, TII->get(MFI.shouldSignWithBKey() ? AArch64::RETAB : AArch64::RETAA)) .copyImplicitOps(*MBBI); @@ -1889,6 +1896,11 @@ BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameDestroy); + if (NeedsWinCFI) { + *HasWinCFI = true; + BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR)) + .setMIFlag(MachineInstr::FrameDestroy); + } } } @@ -1921,11 +1933,15 @@ } auto FinishingTouches = make_scope_exit([&]() { - InsertReturnAddressAuth(MF, MBB); + InsertReturnAddressAuth(MF, MBB, NeedsWinCFI, &HasWinCFI); if (needsShadowCallStackPrologueEpilogue(MF)) emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL); if (EmitCFI) emitCalleeSavedGPRRestores(MBB, MBB.getFirstTerminator()); + if (HasWinCFI) + BuildMI(MBB, MBB.getFirstTerminator(), DL, + TII->get(AArch64::SEH_EpilogEnd)) + .setMIFlag(MachineInstr::FrameDestroy); }); int64_t NumBytes = IsFunclet ? getWinEHFuncletFrameSize(MF) @@ -2073,10 +2089,6 @@ StackOffset::getFixed(NumBytes + (int64_t)AfterCSRPopSize), TII, MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI, EmitCFI, StackOffset::getFixed(NumBytes)); - if (HasWinCFI) - BuildMI(MBB, MBB.getFirstTerminator(), DL, - TII->get(AArch64::SEH_EpilogEnd)) - .setMIFlag(MachineInstr::FrameDestroy); return; } @@ -2169,11 +2181,6 @@ // If we were able to combine the local stack pop with the argument pop, // then we're done. if (NoCalleeSaveRestore || AfterCSRPopSize == 0) { - if (HasWinCFI) { - BuildMI(MBB, MBB.getFirstTerminator(), DL, - TII->get(AArch64::SEH_EpilogEnd)) - .setMIFlag(MachineInstr::FrameDestroy); - } return; } @@ -2218,9 +2225,6 @@ false, NeedsWinCFI, &HasWinCFI, EmitCFI, StackOffset::getFixed(CombineAfterCSRBump ? PrologueSaveSize : 0)); } - if (HasWinCFI) - BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd)) - .setMIFlag(MachineInstr::FrameDestroy); } /// getFrameIndexReference - Provide a base+offset reference to an FI slot for diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1016,6 +1016,7 @@ case AArch64::SEH_PrologEnd: case AArch64::SEH_EpilogStart: case AArch64::SEH_EpilogEnd: + case AArch64::SEH_PACSignLR: return true; } } diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -4255,6 +4255,7 @@ def SEH_PrologEnd : Pseudo<(outs), (ins), []>, Sched<[]>; def SEH_EpilogStart : Pseudo<(outs), (ins), []>, Sched<[]>; def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>; + def SEH_PACSignLR : Pseudo<(outs), (ins), []>, Sched<[]>; } // Pseudo instructions for Windows EH diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp @@ -66,11 +66,13 @@ return {true, false}; } -static bool ShouldSignWithBKey(const Function &F) { +static bool ShouldSignWithBKey(const Function &F, const MachineFunction &MF) { if (!F.hasFnAttribute("sign-return-address-key")) { if (const auto *BKey = mdconst::extract_or_null( F.getParent()->getModuleFlag("sign-return-address-with-bkey"))) return BKey->getZExtValue(); + if (MF.getTarget().getTargetTriple().isOSWindows()) + return true; return false; } @@ -88,7 +90,7 @@ const Function &F = MF->getFunction(); std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F); - SignWithBKey = ShouldSignWithBKey(F); + SignWithBKey = ShouldSignWithBKey(F, *MF); // TODO: skip functions that have no instrumented allocas for optimization IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag); diff --git a/llvm/test/CodeGen/AArch64/wineh-pac.ll b/llvm/test/CodeGen/AArch64/wineh-pac.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/wineh-pac.ll @@ -0,0 +1,66 @@ +; RUN: llc < %s -mtriple=aarch64-windows | FileCheck %s + +define dso_local i32 @func(ptr %g, i32 %a) { +entry: + tail call void %g() #2 + ret i32 %a +} + +define dso_local i32 @func2(ptr %g, i32 %a) "target-features"="+v8.3a" { +entry: + tail call void %g() #2 + ret i32 %a +} + +!llvm.module.flags = !{!0} + +!0 = !{i32 8, !"sign-return-address", i32 1} + +; CHECK-LABEL: func: +; CHECK-NEXT: .seh_proc func +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: hint #27 +; CHECK-NEXT: .seh_pac_sign_lr +; CHECK-NEXT: str x19, [sp, #-16]! +; CHECK-NEXT: .seh_save_reg_x x19, 16 +; CHECK-NEXT: str x30, [sp, #8] +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: .seh_endprologue + +; CHECK: .seh_startepilogue +; CHECK-NEXT: ldr x30, [sp, #8] +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: ldr x19, [sp], #16 +; CHECK-NEXT: .seh_save_reg_x x19, 16 +; CHECK-NEXT: hint #31 +; CHECK-NEXT: .seh_pac_sign_lr +; CHECK-NEXT: .seh_endepilogue +; CHECK-NEXT: ret +; CHECK-NEXT: .seh_endfunclet +; CHECK-NEXT: .seh_endproc + +;; For func2, check that the potentially folded autibsp+ret -> retab +;; is handled correctly - currently we inhibit producing retab here. + +; CHECK-LABEL: func2: +; CHECK-NEXT: .seh_proc func2 +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: pacib x30, sp +; CHECK-NEXT: .seh_pac_sign_lr +; CHECK-NEXT: str x19, [sp, #-16]! +; CHECK-NEXT: .seh_save_reg_x x19, 16 +; CHECK-NEXT: str x30, [sp, #8] +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: .seh_endprologue + +; CHECK: .seh_startepilogue +; CHECK-NEXT: ldr x30, [sp, #8] +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: ldr x19, [sp], #16 +; CHECK-NEXT: .seh_save_reg_x x19, 16 +; CHECK-NEXT: autibsp +; CHECK-NEXT: .seh_pac_sign_lr +; CHECK-NEXT: .seh_endepilogue +; CHECK-NEXT: ret +; CHECK-NEXT: .seh_endfunclet +; CHECK-NEXT: .seh_endproc