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_SignRA: + TS->emitARM64WinCFISignRA(); + 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_SignRA)) + .setMIFlag(MachineInstr::FrameSetup); } } if (EmitCFI && MFnI.isMTETagged()) { @@ -1847,7 +1853,8 @@ } static void InsertReturnAddressAuth(MachineFunction &MF, - MachineBasicBlock &MBB) { + MachineBasicBlock &MBB, bool NeedsWinCFI, + bool *HasWinCFI) { const auto &MFI = *MF.getInfo(); if (!MFI.shouldSignReturnAddress()) return; @@ -1866,7 +1873,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); @@ -1882,6 +1890,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_SignRA)) + .setMIFlag(MachineInstr::FrameDestroy); + } } } @@ -1914,11 +1927,14 @@ } 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) @@ -2066,10 +2082,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; } @@ -2162,11 +2174,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; } @@ -2211,9 +2218,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_SignRA: 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 @@ -4259,6 +4259,7 @@ def SEH_PrologEnd : Pseudo<(outs), (ins), []>, Sched<[]>; def SEH_EpilogStart : Pseudo<(outs), (ins), []>, Sched<[]>; def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>; + def SEH_SignRA : 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,34 @@ +; 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 +} + +!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_sign_ra +; 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_sign_ra +; CHECK-NEXT: .seh_endepilogue +; CHECK-NEXT: ret +; CHECK-NEXT: .seh_endfunclet +; CHECK-NEXT: .seh_endproc