[AArch64] Generate SEH info for PAC instructions

Without this, unwinding through functions that does use PAC
would fail, if PAC actually was active.

Differential Revision: https://reviews.llvm.org/D135103
This commit is contained in:
Martin Storsjö 2022-10-01 18:49:32 +03:00
parent 918f6f581d
commit bd3fa31887
6 changed files with 96 additions and 18 deletions

View File

@ -1661,6 +1661,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
case AArch64::SEH_EpilogEnd:
TS->emitARM64WinCFIEpilogEnd();
return;
case AArch64::SEH_PACSignLR:
TS->emitARM64WinCFIPACSignLR();
return;
}
// Finally, do the automated lowerings for everything else.

View File

@ -1409,6 +1409,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
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 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
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 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
}
}
static void InsertReturnAddressAuth(MachineFunction &MF,
MachineBasicBlock &MBB) {
static void InsertReturnAddressAuth(MachineFunction &MF, MachineBasicBlock &MBB,
bool NeedsWinCFI, bool *HasWinCFI) {
const auto &MFI = *MF.getInfo<AArch64FunctionInfo>();
if (!MFI.shouldSignReturnAddress())
return;
@ -1873,7 +1879,8 @@ static void InsertReturnAddressAuth(MachineFunction &MF,
// 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 @@ static void InsertReturnAddressAuth(MachineFunction &MF,
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 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
}
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 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
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 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
// 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 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
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

View File

@ -1016,6 +1016,7 @@ bool AArch64InstrInfo::isSEHInstruction(const MachineInstr &MI) {
case AArch64::SEH_PrologEnd:
case AArch64::SEH_EpilogStart:
case AArch64::SEH_EpilogEnd:
case AArch64::SEH_PACSignLR:
return true;
}
}

View File

@ -4255,6 +4255,7 @@ let isPseudo = 1 in {
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

View File

@ -66,11 +66,13 @@ static std::pair<bool, bool> GetSignReturnAddress(const Function &F) {
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<ConstantInt>(
F.getParent()->getModuleFlag("sign-return-address-with-bkey")))
return BKey->getZExtValue();
if (MF.getTarget().getTargetTriple().isOSWindows())
return true;
return false;
}
@ -88,7 +90,7 @@ AArch64FunctionInfo::AArch64FunctionInfo(MachineFunction &MF_) : MF(&MF_) {
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);

View File

@ -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