Skip to content

Commit 7029b8d

Browse files
jroelofsdtellenbach
andcommitted
[AArch64][PAC] Move MachO (pro|epi)logue PAC to generic AArch64PointerAuth infra. NFC
rdar://163365479 Co-Authored-By: David Tellenbach <dtellenbach@apple.com>
1 parent 8f019f1 commit 7029b8d

File tree

6 files changed

+93
-101
lines changed

6 files changed

+93
-101
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,8 @@ void AArch64FrameLowering::resetCFIToInitialState(
723723
CFIBuilder.buildDefCFA(AArch64::SP, 0);
724724

725725
// Flip the RA sign state.
726-
if (MFI.shouldSignReturnAddress(MF))
726+
if (MFI.shouldSignReturnAddress(MF) &&
727+
!MF.getTarget().getTargetTriple().isOSDarwin())
727728
MFI.branchProtectionPAuthLR() ? CFIBuilder.buildNegateRAStateWithPC()
728729
: CFIBuilder.buildNegateRAState();
729730

@@ -984,7 +985,8 @@ bool AArch64FrameLowering::shouldSignReturnAddressEverywhere(
984985
if (MF.getTarget().getMCAsmInfo()->usesWindowsCFI())
985986
return false;
986987
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
987-
bool SignReturnAddressAll = AFI->shouldSignReturnAddress(/*SpillsLR=*/false);
988+
bool SignReturnAddressAll =
989+
AFI->shouldSignReturnAddress(MF, /*SpillsLR=*/false);
988990
return SignReturnAddressAll;
989991
}
990992

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9555,8 +9555,10 @@ outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a,
95559555
const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
95569556
const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
95579557

9558-
return MFIa->shouldSignReturnAddress(false) == MFIb->shouldSignReturnAddress(false) &&
9559-
MFIa->shouldSignReturnAddress(true) == MFIb->shouldSignReturnAddress(true);
9558+
return MFIa->shouldSignReturnAddress(*a.getMF(), false) ==
9559+
MFIb->shouldSignReturnAddress(*b.getMF(), false) &&
9560+
MFIa->shouldSignReturnAddress(*a.getMF(), true) ==
9561+
MFIb->shouldSignReturnAddress(*b.getMF(), true);
95609562
}
95619563

95629564
static bool
@@ -9626,10 +9628,8 @@ AArch64InstrInfo::getOutliningCandidateInfo(
96269628
// Performing a tail call may require extra checks when PAuth is enabled.
96279629
// If PAuth is disabled, set it to zero for uniformity.
96289630
unsigned NumBytesToCheckLRInTCEpilogue = 0;
9629-
if (RepeatedSequenceLocs[0]
9630-
.getMF()
9631-
->getInfo<AArch64FunctionInfo>()
9632-
->shouldSignReturnAddress(true)) {
9631+
const MachineFunction &MF = *RepeatedSequenceLocs[0].getMF();
9632+
if (MF.getInfo<AArch64FunctionInfo>()->shouldSignReturnAddress(MF, true)) {
96339633
// One PAC and one AUT instructions
96349634
NumBytesToCreateFrame += 8;
96359635

@@ -10433,7 +10433,7 @@ void AArch64InstrInfo::buildOutlinedFrame(
1043310433
Et = MBB.insert(Et, LDRXpost);
1043410434
}
1043510435

10436-
bool ShouldSignReturnAddr = FI->shouldSignReturnAddress(!IsLeafFunction);
10436+
bool ShouldSignReturnAddr = FI->shouldSignReturnAddress(MF, !IsLeafFunction);
1043710437

1043810438
// If this is a tail call outlined function, then there's already a return.
1043910439
if (OF.FrameConstructionID == MachineOutlinerTailCall ||

llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ static std::pair<bool, bool> GetSignReturnAddress(const Function &F,
8686
}
8787

8888
static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) {
89-
if (!STI.getTargetTriple().isOSBinFormatMachO() &&
90-
F.hasFnAttribute("ptrauth-returns"))
89+
if (F.hasFnAttribute("ptrauth-returns"))
9190
return true;
9291
if (!F.hasFnAttribute("sign-return-address-key")) {
9392
if (STI.getTargetTriple().isOSWindows())
@@ -173,7 +172,18 @@ MachineFunctionInfo *AArch64FunctionInfo::clone(
173172
return DestMF.cloneInfo<AArch64FunctionInfo>(*this);
174173
}
175174

176-
bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const {
175+
static bool shouldAuthenticateLR(const MachineFunction &MF) {
176+
// Return address authentication can be enabled at the function level, using
177+
// the "ptrauth-returns" attribute.
178+
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
179+
return Subtarget.isTargetMachO() &&
180+
MF.getFunction().hasFnAttribute("ptrauth-returns");
181+
}
182+
183+
bool AArch64FunctionInfo::shouldSignReturnAddress(const MachineFunction &MF,
184+
bool SpillsLR) const {
185+
if (SpillsLR && shouldAuthenticateLR(MF))
186+
return true;
177187
if (!SignReturnAddress)
178188
return false;
179189
if (SignReturnAddressAll)
@@ -189,7 +199,7 @@ static bool isLRSpilled(const MachineFunction &MF) {
189199

190200
bool AArch64FunctionInfo::shouldSignReturnAddress(
191201
const MachineFunction &MF) const {
192-
return shouldSignReturnAddress(isLRSpilled(MF));
202+
return shouldSignReturnAddress(MF, isLRSpilled(MF));
193203
}
194204

195205
bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue(

llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
596596
}
597597

598598
bool shouldSignReturnAddress(const MachineFunction &MF) const;
599-
bool shouldSignReturnAddress(bool SpillsLR) const;
599+
bool shouldSignReturnAddress(const MachineFunction &MF, bool SpillsLR) const;
600600

601601
bool needsShadowCallStackPrologueEpilogue(MachineFunction &MF) const;
602602

llvm/lib/Target/AArch64/AArch64PointerAuth.cpp

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
#include "AArch64Subtarget.h"
1515
#include "llvm/CodeGen/CFIInstBuilder.h"
1616
#include "llvm/CodeGen/MachineBasicBlock.h"
17+
#include "llvm/CodeGen/MachineFrameInfo.h"
18+
#include "llvm/CodeGen/MachineInstr.h"
1719
#include "llvm/CodeGen/MachineInstrBuilder.h"
1820
#include "llvm/CodeGen/MachineModuleInfo.h"
21+
#include "llvm/IR/CallingConv.h"
1922

2023
using namespace llvm;
2124
using namespace llvm::AArch64PAuth;
@@ -96,6 +99,9 @@ static void emitPACCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
9699
if (!EmitCFI)
97100
return;
98101

102+
if (MBB.getParent()->getTarget().getTargetTriple().isOSDarwin())
103+
return;
104+
99105
auto &MF = *MBB.getParent();
100106
auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
101107

@@ -116,7 +122,7 @@ void AArch64PointerAuth::signLR(MachineFunction &MF,
116122
// Debug location must be unknown, see AArch64FrameLowering::emitPrologue.
117123
DebugLoc DL;
118124

119-
if (UseBKey) {
125+
if (UseBKey && !MF.getTarget().getTargetTriple().isOSDarwin()) {
120126
BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY))
121127
.setMIFlag(MachineInstr::FrameSetup);
122128
}
@@ -133,17 +139,15 @@ void AArch64PointerAuth::signLR(MachineFunction &MF,
133139
if (MFnI.branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
134140
emitPACCFI(MBB, MBBI, MachineInstr::FrameSetup, EmitCFI);
135141
BuildMI(MBB, MBBI, DL,
136-
TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSPPC
137-
: AArch64::PACIASPPC))
142+
TII->get(UseBKey ? AArch64::PACIBSPPC : AArch64::PACIASPPC))
138143
.setMIFlag(MachineInstr::FrameSetup)
139144
->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
140145
} else {
141146
BuildPACM(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameSetup);
142147
if (MFnI.branchProtectionPAuthLR())
143148
emitPACCFI(MBB, MBBI, MachineInstr::FrameSetup, EmitCFI);
144149
BuildMI(MBB, MBBI, DL,
145-
TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSP
146-
: AArch64::PACIASP))
150+
TII->get(UseBKey ? AArch64::PACIBSP : AArch64::PACIASP))
147151
.setMIFlag(MachineInstr::FrameSetup)
148152
->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
149153
if (!MFnI.branchProtectionPAuthLR())
@@ -178,11 +182,41 @@ void AArch64PointerAuth::authenticateLR(
178182
// instructions, namely RETA{A,B}, that can be used instead. In this case the
179183
// DW_CFA_AARCH64_negate_ra_state can't be emitted.
180184
bool TerminatorIsCombinable =
181-
TI != MBB.end() && TI->getOpcode() == AArch64::RET;
185+
TI != MBB.end() && (TI->getOpcode() == AArch64::RET ||
186+
TI->getOpcode() == AArch64::RET_ReallyLR);
182187
MCSymbol *PACSym = MFnI->getSigningInstrLabel();
183188

189+
const MachineFrameInfo &MFI = MF.getFrameInfo();
190+
bool IsLRSpilled =
191+
llvm::any_of(MFI.getCalleeSavedInfo(), [](const CalleeSavedInfo &Info) {
192+
return Info.getReg() == AArch64::LR;
193+
});
194+
195+
// In functions with popless epilogues (swiftcorocc calling convention with
196+
// llvm.ret.popless), some returns don't restore SP, so we can't use RETAB
197+
// because the authenticating discriminator (SP) won't match the signing
198+
// discriminator. We need to check if this specific block restores SP.
199+
// If SP is restored before the return, we can use RETAB; otherwise we need
200+
// to compute the discriminator from FP and use AUTIB + separate RET.
201+
bool IsSwiftCoroPartialReturn = [&]() {
202+
if (!MFnI->hasPoplessEpilogue())
203+
return false;
204+
205+
// Check if any instruction in the epilogue modifies SP.
206+
if (llvm::any_of(make_range(MBB.begin(), MBB.getFirstTerminator()),
207+
[&](const MachineInstr &I) {
208+
return I.getFlag(MachineInstr::FrameDestroy) &&
209+
I.modifiesRegister(AArch64::SP,
210+
Subtarget->getRegisterInfo());
211+
}))
212+
return false;
213+
214+
return true;
215+
}();
216+
184217
if (Subtarget->hasPAuth() && TerminatorIsCombinable && !NeedsWinCFI &&
185-
!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) {
218+
!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack) &&
219+
!IsSwiftCoroPartialReturn) {
186220
if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
187221
assert(PACSym && "No PAC instruction to refer to");
188222
emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
@@ -198,6 +232,31 @@ void AArch64PointerAuth::authenticateLR(
198232
.setMIFlag(MachineInstr::FrameDestroy);
199233
}
200234
MBB.erase(TI);
235+
} else if (IsSwiftCoroPartialReturn && IsLRSpilled) {
236+
// For popless epilogues that don't restore SP, we can't use RETAB because
237+
// SP doesn't match. Instead, compute the correct discriminator from FP.
238+
const auto *TRI = Subtarget->getRegisterInfo();
239+
240+
MachineBasicBlock::iterator EpilogStartI = MBB.getFirstTerminator();
241+
MachineBasicBlock::iterator Begin = MBB.begin();
242+
while (EpilogStartI != Begin) {
243+
--EpilogStartI;
244+
if (!EpilogStartI->getFlag(MachineInstr::FrameDestroy)) {
245+
++EpilogStartI;
246+
break;
247+
}
248+
if (EpilogStartI->readsRegister(AArch64::X16, TRI) ||
249+
EpilogStartI->modifiesRegister(AArch64::X16, TRI))
250+
report_fatal_error("unable to use x16 for popless ret LR auth");
251+
}
252+
253+
emitFrameOffset(MBB, EpilogStartI, DL, AArch64::X16, AArch64::FP,
254+
StackOffset::getFixed(16), TII, MachineInstr::FrameDestroy);
255+
emitPACCFI(MBB, MBBI, MachineInstr::FrameDestroy, EmitAsyncCFI);
256+
BuildMI(MBB, TI, DL, TII->get(AArch64::AUTIB), AArch64::LR)
257+
.addUse(AArch64::LR)
258+
.addUse(AArch64::X16)
259+
.setMIFlag(MachineInstr::FrameDestroy);
201260
} else {
202261
if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
203262
assert(PACSym && "No PAC instruction to refer to");

llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp

Lines changed: 1 addition & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,6 @@ void AArch64PrologueEmitter::verifyPrologueClobbers() const {
536536
}
537537
#endif
538538

539-
static bool shouldAuthenticateLR(const MachineFunction &MF) {
540-
// Return address authentication can be enabled at the function level, using
541-
// the "ptrauth-returns" attribute.
542-
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
543-
return Subtarget.isTargetMachO() &&
544-
MF.getFunction().hasFnAttribute("ptrauth-returns");
545-
}
546-
547539
void AArch64PrologueEmitter::determineLocalsStackSize(
548540
uint64_t StackSize, uint64_t PrologueSaveSize) {
549541
AFI->setLocalStackSize(StackSize - PrologueSaveSize);
@@ -725,18 +717,6 @@ void AArch64PrologueEmitter::emitPrologue() {
725717
BuildMI(MBB, PrologueBeginI, DL, TII->get(AArch64::EMITMTETAGGED))
726718
.setMIFlag(MachineInstr::FrameSetup);
727719

728-
// If we're saving LR, sign it first.
729-
if (shouldAuthenticateLR(MF)) {
730-
if (LLVM_UNLIKELY(!Subtarget.hasPAuth()))
731-
report_fatal_error("arm64e LR authentication requires ptrauth");
732-
for (const CalleeSavedInfo &Info : MFI.getCalleeSavedInfo()) {
733-
if (Info.getReg() != AArch64::LR)
734-
continue;
735-
BuildMI(MBB, PrologueBeginI, DL, TII->get(AArch64::PACIBSP))
736-
.setMIFlags(MachineInstr::FrameSetup);
737-
}
738-
}
739-
740720
// We signal the presence of a Swift extended frame to external tools by
741721
// storing FP with 0b0001 in bits 63:60. In normal userland operation a simple
742722
// ORR is sufficient, it is assumed a Swift kernel would initialize the TBI
@@ -1436,66 +1416,6 @@ void AArch64EpilogueEmitter::emitEpilogue() {
14361416
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
14371417
return;
14381418

1439-
// If we're restoring LR, authenticate it before returning.
1440-
// Use scope_exit to ensure we do that last on all return paths.
1441-
auto InsertAuthLROnExit = make_scope_exit([&]() {
1442-
if (shouldAuthenticateLR(MF)) {
1443-
if (LLVM_UNLIKELY(!Subtarget.hasPAuth()))
1444-
report_fatal_error("arm64e LR authentication requires ptrauth");
1445-
for (const CalleeSavedInfo &Info : MFI.getCalleeSavedInfo()) {
1446-
if (Info.getReg() != AArch64::LR)
1447-
continue;
1448-
MachineBasicBlock::iterator TI = MBB.getFirstTerminator();
1449-
1450-
// When we're doing a popless ret (i.e., that doesn't restore SP), we
1451-
// can't rely on the exit SP being the same as the entry, but they need
1452-
// to match for the LR auth to succeed. Instead, derive the entry SP
1453-
// from our FP (using a -16 static offset for the size of the frame
1454-
// record itself), save that into X16, and use that as the discriminator
1455-
// in an AUTIB.
1456-
if (IsSwiftCoroPartialReturn) {
1457-
const auto *TRI = Subtarget.getRegisterInfo();
1458-
1459-
MachineBasicBlock::iterator EpilogStartI = MBB.getFirstTerminator();
1460-
MachineBasicBlock::iterator Begin = MBB.begin();
1461-
while (EpilogStartI != Begin) {
1462-
--EpilogStartI;
1463-
if (!EpilogStartI->getFlag(MachineInstr::FrameDestroy)) {
1464-
++EpilogStartI;
1465-
break;
1466-
}
1467-
if (EpilogStartI->readsRegister(AArch64::X16, TRI) ||
1468-
EpilogStartI->modifiesRegister(AArch64::X16, TRI))
1469-
report_fatal_error("unable to use x16 for popless ret LR auth");
1470-
}
1471-
1472-
emitFrameOffset(MBB, EpilogStartI, DL, AArch64::X16, AArch64::FP,
1473-
StackOffset::getFixed(16), TII,
1474-
MachineInstr::FrameDestroy);
1475-
BuildMI(MBB, TI, DL, TII->get(AArch64::AUTIB), AArch64::LR)
1476-
.addUse(AArch64::LR)
1477-
.addUse(AArch64::X16)
1478-
.setMIFlag(MachineInstr::FrameDestroy);
1479-
return;
1480-
}
1481-
1482-
if (TI != MBB.end() && TI->getOpcode() == AArch64::RET_ReallyLR) {
1483-
// If there is a terminator and it's a RET, we can fold AUTH into it.
1484-
// Be careful to keep the implicitly returned registers.
1485-
// By now, we don't need the ReallyLR pseudo, since it's only there
1486-
// to make it possible for LR to be used for non-RET purposes, and
1487-
// that happens in RA and PEI.
1488-
BuildMI(MBB, TI, DL, TII->get(AArch64::RETAB)).copyImplicitOps(*TI);
1489-
MBB.erase(TI);
1490-
} else {
1491-
// Otherwise, we could be in a shrink-wrapped or tail-calling block.
1492-
BuildMI(MBB, TI, DL, TII->get(AArch64::AUTIBSP));
1493-
}
1494-
}
1495-
}
1496-
});
1497-
1498-
14991419
// How much of the stack used by incoming arguments this function is expected
15001420
// to restore in this particular epilogue.
15011421
int64_t ArgumentStackToRestore = AFL.getArgumentStackToRestore(MF, MBB);
@@ -1923,6 +1843,7 @@ void AArch64EpilogueEmitter::finalizeEpilogue() const {
19231843
}
19241844
if (EmitCFI)
19251845
emitCalleeSavedGPRRestores(MBB.getFirstTerminator());
1846+
19261847
if (AFI->shouldSignReturnAddress(MF)) {
19271848
// If pac-ret+leaf is in effect, PAUTH_EPILOGUE pseudo instructions
19281849
// are inserted by emitPacRetPlusLeafHardening().

0 commit comments

Comments
 (0)