Skip to content

Commit f65267e

Browse files
Revert "Reland [AArch64][MachineOutliner] Return address signing for outlined functions"
This reverts commit 02760b7. The original commit is not asan clean. http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/37147/steps/check-llvm%20asan/logs/stdio
1 parent 3c50f25 commit f65267e

12 files changed

+8
-1271
lines changed

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 8 additions & 284 deletions
Original file line numberDiff line numberDiff line change
@@ -5412,195 +5412,21 @@ AArch64InstrInfo::findRegisterToSaveLRTo(const outliner::Candidate &C) const {
54125412
return 0u;
54135413
}
54145414

5415-
static bool
5416-
outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a,
5417-
const outliner::Candidate &b) {
5418-
const Function &Fa = a.getMF()->getFunction();
5419-
const Function &Fb = b.getMF()->getFunction();
5420-
5421-
// If none of the functions have the "sign-return-address" attribute their
5422-
// signing behaviour is equal
5423-
if (!Fa.hasFnAttribute("sign-return-address") &&
5424-
!Fb.hasFnAttribute("sign-return-address")) {
5425-
return true;
5426-
}
5427-
5428-
// If both functions have the "sign-return-address" attribute their signing
5429-
// behaviour is equal, if the values of the attributes are equal
5430-
if (Fa.hasFnAttribute("sign-return-address") &&
5431-
Fb.hasFnAttribute("sign-return-address")) {
5432-
StringRef ScopeA =
5433-
Fa.getFnAttribute("sign-return-address").getValueAsString();
5434-
StringRef ScopeB =
5435-
Fb.getFnAttribute("sign-return-address").getValueAsString();
5436-
return ScopeA.equals(ScopeB);
5437-
}
5438-
5439-
// If function B doesn't have the "sign-return-address" attribute but A does,
5440-
// the functions' signing behaviour is equal if A's value for
5441-
// "sign-return-address" is "none" and vice versa.
5442-
if (Fa.hasFnAttribute("sign-return-address")) {
5443-
StringRef ScopeA =
5444-
Fa.getFnAttribute("sign-return-address").getValueAsString();
5445-
return ScopeA.equals("none");
5446-
}
5447-
5448-
if (Fb.hasFnAttribute("sign-return-address")) {
5449-
StringRef ScopeB =
5450-
Fb.getFnAttribute("sign-return-address").getValueAsString();
5451-
return ScopeB.equals("none");
5452-
}
5453-
5454-
llvm_unreachable("Unkown combination of sign-return-address attributes");
5455-
}
5456-
5457-
static bool
5458-
outliningCandidatesSigningKeyConsensus(const outliner::Candidate &a,
5459-
const outliner::Candidate &b) {
5460-
const Function &Fa = a.getMF()->getFunction();
5461-
const Function &Fb = b.getMF()->getFunction();
5462-
5463-
// If none of the functions have the "sign-return-address-key" attribute
5464-
// their keys are equal
5465-
if (!Fa.hasFnAttribute("sign-return-address-key") &&
5466-
!Fb.hasFnAttribute("sign-return-address-key")) {
5467-
return true;
5468-
}
5469-
5470-
// If both functions have the "sign-return-address-key" attribute their
5471-
// keys are equal if the values of "sign-return-address-key" are equal
5472-
if (Fa.hasFnAttribute("sign-return-address-key") &&
5473-
Fb.hasFnAttribute("sign-return-address-key")) {
5474-
StringRef KeyA =
5475-
Fa.getFnAttribute("sign-return-address-key").getValueAsString();
5476-
StringRef KeyB =
5477-
Fb.getFnAttribute("sign-return-address-key").getValueAsString();
5478-
return KeyA.equals(KeyB);
5479-
}
5480-
5481-
// If B doesn't have the "sign-return-address-key" attribute, both keys are
5482-
// equal, if function a has the default key (a_key)
5483-
if (Fa.hasFnAttribute("sign-return-address-key")) {
5484-
StringRef KeyA =
5485-
Fa.getFnAttribute("sign-return-address-key").getValueAsString();
5486-
return KeyA.equals_lower("a_key");
5487-
}
5488-
5489-
if (Fb.hasFnAttribute("sign-return-address-key")) {
5490-
StringRef KeyB =
5491-
Fb.getFnAttribute("sign-return-address-key").getValueAsString();
5492-
return KeyB.equals_lower("a_key");
5493-
}
5494-
5495-
llvm_unreachable("Unkown combination of sign-return-address-key attributes");
5496-
}
5497-
5498-
static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a,
5499-
const outliner::Candidate &b) {
5500-
const AArch64Subtarget &SubtargetA =
5501-
a.getMF()->getSubtarget<AArch64Subtarget>();
5502-
const AArch64Subtarget &SubtargetB =
5503-
b.getMF()->getSubtarget<AArch64Subtarget>();
5504-
return SubtargetA.hasV8_3aOps() == SubtargetB.hasV8_3aOps();
5505-
}
5506-
5507-
outliner::OutlinedFunction AArch64InstrInfo::getOutliningCandidateInfo(
5415+
outliner::OutlinedFunction
5416+
AArch64InstrInfo::getOutliningCandidateInfo(
55085417
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
55095418
outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
55105419
unsigned SequenceSize =
55115420
std::accumulate(FirstCand.front(), std::next(FirstCand.back()), 0,
55125421
[this](unsigned Sum, const MachineInstr &MI) {
55135422
return Sum + getInstSizeInBytes(MI);
55145423
});
5515-
unsigned NumBytesToCreateFrame = 0;
5516-
5517-
// We only allow outlining for functions having exactly matching return
5518-
// address signing attributes, i.e., all share the same value for the
5519-
// attribute "sign-return-address" and all share the same type of key they
5520-
// are signed with.
5521-
// Additionally we require all functions to simultaniously either support
5522-
// v8.3a features or not. Otherwise an outlined function could get signed
5523-
// using dedicated v8.3 instructions and a call from a function that doesn't
5524-
// support v8.3 instructions would therefore be invalid.
5525-
if (std::adjacent_find(
5526-
RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
5527-
[](const outliner::Candidate &a, const outliner::Candidate &b) {
5528-
// Return true if a and b are non-equal w.r.t. return address
5529-
// signing or support of v8.3a features
5530-
if (outliningCandidatesSigningScopeConsensus(a, b) &&
5531-
outliningCandidatesSigningKeyConsensus(a, b) &&
5532-
outliningCandidatesV8_3OpsConsensus(a, b)) {
5533-
return false;
5534-
}
5535-
return true;
5536-
}) != RepeatedSequenceLocs.end()) {
5537-
return outliner::OutlinedFunction();
5538-
}
5539-
5540-
// Since at this point all candidates agree on their return address signing
5541-
// picking just one is fine. If the candidate functions potentially sign their
5542-
// return addresses, the outlined function should do the same. Note that in
5543-
// the case of "sign-return-address"="non-leaf" this is an assumption: It is
5544-
// not certainly true that the outlined function will have to sign its return
5545-
// address but this decision is made later, when the decision to outline
5546-
// has already been made.
5547-
// The same holds for the number of additional instructions we need: On
5548-
// v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is
5549-
// necessary. However, at this point we don't know if the outlined function
5550-
// will have a RET instruction so we assume the worst.
5551-
const Function &FCF = FirstCand.getMF()->getFunction();
5552-
const TargetRegisterInfo &TRI = getRegisterInfo();
5553-
if (FCF.hasFnAttribute("sign-return-address")) {
5554-
// One PAC and one AUT instructions
5555-
NumBytesToCreateFrame += 8;
5556-
5557-
// We have to check if sp modifying instructions would get outlined.
5558-
// If so we only allow outlining if sp is unchanged overall, so matching
5559-
// sub and add instructions are okay to outline, all other sp modifications
5560-
// are not
5561-
auto hasIllegalSPModification = [&TRI](outliner::Candidate &C) {
5562-
int SPValue = 0;
5563-
MachineBasicBlock::iterator MBBI = C.front();
5564-
for (;;) {
5565-
if (MBBI->modifiesRegister(AArch64::SP, &TRI)) {
5566-
switch (MBBI->getOpcode()) {
5567-
case AArch64::ADDXri:
5568-
case AArch64::ADDWri:
5569-
assert(MBBI->getNumOperands() == 4 && "Wrong number of operands");
5570-
assert(MBBI->getOperand(2).isImm() &&
5571-
"Expected operand to be immediate");
5572-
SPValue += MBBI->getOperand(2).getImm();
5573-
break;
5574-
case AArch64::SUBXri:
5575-
case AArch64::SUBWri:
5576-
assert(MBBI->getNumOperands() == 4 && "Wrong number of operands");
5577-
assert(MBBI->getOperand(2).isImm() &&
5578-
"Expected operand to be immediate");
5579-
SPValue -= MBBI->getOperand(2).getImm();
5580-
break;
5581-
default:
5582-
return true;
5583-
}
5584-
}
5585-
if (MBBI == C.back())
5586-
break;
5587-
++MBBI;
5588-
}
5589-
if (SPValue)
5590-
return true;
5591-
return false;
5592-
};
5593-
// Remove candidates with illegal stack modifying instructions
5594-
RepeatedSequenceLocs.erase(std::remove_if(RepeatedSequenceLocs.begin(),
5595-
RepeatedSequenceLocs.end(),
5596-
hasIllegalSPModification),
5597-
RepeatedSequenceLocs.end());
5598-
}
55995424

56005425
// Properties about candidate MBBs that hold for all of them.
56015426
unsigned FlagsSetInAll = 0xF;
56025427

56035428
// Compute liveness information for each candidate, and set FlagsSetInAll.
5429+
const TargetRegisterInfo &TRI = getRegisterInfo();
56045430
std::for_each(RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
56055431
[&FlagsSetInAll](outliner::Candidate &C) {
56065432
FlagsSetInAll &= C.Flags;
@@ -5656,7 +5482,7 @@ outliner::OutlinedFunction AArch64InstrInfo::getOutliningCandidateInfo(
56565482
};
56575483

56585484
unsigned FrameID = MachineOutlinerDefault;
5659-
NumBytesToCreateFrame += 4;
5485+
unsigned NumBytesToCreateFrame = 4;
56605486

56615487
bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
56625488
return C.getMF()->getFunction().hasFnAttribute("branch-target-enforcement");
@@ -5925,19 +5751,6 @@ AArch64InstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
59255751
MachineFunction *MF = MBB->getParent();
59265752
AArch64FunctionInfo *FuncInfo = MF->getInfo<AArch64FunctionInfo>();
59275753

5928-
// Don't outline anything used for return address signing. The outlined
5929-
// function will get signed later if needed
5930-
switch (MI.getOpcode()) {
5931-
case AArch64::PACIASP:
5932-
case AArch64::PACIBSP:
5933-
case AArch64::AUTIASP:
5934-
case AArch64::AUTIBSP:
5935-
case AArch64::RETAA:
5936-
case AArch64::RETAB:
5937-
case AArch64::EMITBKEY:
5938-
return outliner::InstrType::Illegal;
5939-
}
5940-
59415754
// Don't outline LOHs.
59425755
if (FuncInfo->getLOHRelated().count(&MI))
59435756
return outliner::InstrType::Illegal;
@@ -6090,59 +5903,6 @@ void AArch64InstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
60905903
}
60915904
}
60925905

6093-
static void signOutlinedFunction(MachineFunction &MF, MachineBasicBlock &MBB,
6094-
bool ShouldSignReturnAddr,
6095-
bool ShouldSignReturnAddrWithAKey) {
6096-
if (ShouldSignReturnAddr) {
6097-
MachineBasicBlock::iterator MBBPAC = MBB.begin();
6098-
MachineBasicBlock::iterator MBBAUT = MBB.getFirstTerminator();
6099-
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
6100-
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
6101-
DebugLoc DL;
6102-
6103-
if (MBBAUT != MBB.end())
6104-
DL = MBBAUT->getDebugLoc();
6105-
6106-
// At the very beginning of the basic block we insert the following
6107-
// depending on the key type
6108-
//
6109-
// a_key: b_key:
6110-
// PACIASP EMITBKEY
6111-
// CFI_INSTRUCTION PACIBSP
6112-
// CFI_INSTRUCTION
6113-
if (ShouldSignReturnAddrWithAKey) {
6114-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::PACIASP))
6115-
.setMIFlag(MachineInstr::FrameSetup);
6116-
} else {
6117-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::EMITBKEY))
6118-
.setMIFlag(MachineInstr::FrameSetup);
6119-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::PACIBSP))
6120-
.setMIFlag(MachineInstr::FrameSetup);
6121-
}
6122-
unsigned CFIIndex =
6123-
MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
6124-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::CFI_INSTRUCTION))
6125-
.addCFIIndex(CFIIndex)
6126-
.setMIFlags(MachineInstr::FrameSetup);
6127-
6128-
// If v8.3a features are available we can replace a RET instruction by
6129-
// RETAA or RETAB and omit the AUT instructions
6130-
if (Subtarget.hasV8_3aOps() && MBBAUT != MBB.end() &&
6131-
MBBAUT->getOpcode() == AArch64::RET) {
6132-
BuildMI(MBB, MBBAUT, DL,
6133-
TII->get(ShouldSignReturnAddrWithAKey ? AArch64::RETAA
6134-
: AArch64::RETAB))
6135-
.copyImplicitOps(*MBBAUT);
6136-
MBB.erase(MBBAUT);
6137-
} else {
6138-
BuildMI(MBB, MBBAUT, DL,
6139-
TII->get(ShouldSignReturnAddrWithAKey ? AArch64::AUTIASP
6140-
: AArch64::AUTIBSP))
6141-
.setMIFlag(MachineInstr::FrameDestroy);
6142-
}
6143-
}
6144-
}
6145-
61465906
void AArch64InstrInfo::buildOutlinedFrame(
61475907
MachineBasicBlock &MBB, MachineFunction &MF,
61485908
const outliner::OutlinedFunction &OF) const {
@@ -6158,28 +5918,23 @@ void AArch64InstrInfo::buildOutlinedFrame(
61585918
TailOpcode = AArch64::TCRETURNriALL;
61595919
}
61605920
MachineInstr *TC = BuildMI(MF, DebugLoc(), get(TailOpcode))
6161-
.add(Call->getOperand(0))
6162-
.addImm(0);
5921+
.add(Call->getOperand(0))
5922+
.addImm(0);
61635923
MBB.insert(MBB.end(), TC);
61645924
Call->eraseFromParent();
61655925
}
61665926

6167-
bool IsLeafFunction = true;
6168-
61695927
// Is there a call in the outlined range?
6170-
auto IsNonTailCall = [](const MachineInstr &MI) {
5928+
auto IsNonTailCall = [](MachineInstr &MI) {
61715929
return MI.isCall() && !MI.isReturn();
61725930
};
6173-
61745931
if (std::any_of(MBB.instr_begin(), MBB.instr_end(), IsNonTailCall)) {
61755932
// Fix up the instructions in the range, since we're going to modify the
61765933
// stack.
61775934
assert(OF.FrameConstructionID != MachineOutlinerDefault &&
61785935
"Can only fix up stack references once");
61795936
fixupPostOutline(MBB);
61805937

6181-
IsLeafFunction = false;
6182-
61835938
// LR has to be a live in so that we can save it.
61845939
MBB.addLiveIn(AArch64::LR);
61855940

@@ -6226,47 +5981,16 @@ void AArch64InstrInfo::buildOutlinedFrame(
62265981
Et = MBB.insert(Et, LDRXpost);
62275982
}
62285983

6229-
// If a bunch of candidates reach this point they must agree on their return
6230-
// address signing. It is therefore enough to just consider the signing
6231-
// behaviour of one of them
6232-
const Function &CF = OF.Candidates.front().getMF()->getFunction();
6233-
bool ShouldSignReturnAddr = false;
6234-
if (CF.hasFnAttribute("sign-return-address")) {
6235-
StringRef Scope =
6236-
CF.getFnAttribute("sign-return-address").getValueAsString();
6237-
if (Scope.equals("all"))
6238-
ShouldSignReturnAddr = true;
6239-
else if (Scope.equals("non-leaf") && !IsLeafFunction)
6240-
ShouldSignReturnAddr = true;
6241-
}
6242-
6243-
// a_key is the default
6244-
bool ShouldSignReturnAddrWithAKey = true;
6245-
if (CF.hasFnAttribute("sign-return-address-key")) {
6246-
const StringRef Key =
6247-
CF.getFnAttribute("sign-return-address-key").getValueAsString();
6248-
// Key can either be a_key or b_key
6249-
assert((Key.equals_lower("a_key") || Key.equals_lower("b_key")) &&
6250-
"Return address signing key must be either a_key or b_key");
6251-
ShouldSignReturnAddrWithAKey = Key.equals_lower("a_key");
6252-
}
6253-
62545984
// If this is a tail call outlined function, then there's already a return.
62555985
if (OF.FrameConstructionID == MachineOutlinerTailCall ||
6256-
OF.FrameConstructionID == MachineOutlinerThunk) {
6257-
signOutlinedFunction(MF, MBB, ShouldSignReturnAddr,
6258-
ShouldSignReturnAddrWithAKey);
5986+
OF.FrameConstructionID == MachineOutlinerThunk)
62595987
return;
6260-
}
62615988

62625989
// It's not a tail call, so we have to insert the return ourselves.
62635990
MachineInstr *ret = BuildMI(MF, DebugLoc(), get(AArch64::RET))
62645991
.addReg(AArch64::LR, RegState::Undef);
62655992
MBB.insert(MBB.end(), ret);
62665993

6267-
signOutlinedFunction(MF, MBB, ShouldSignReturnAddr,
6268-
ShouldSignReturnAddrWithAKey);
6269-
62705994
// Did we have to modify the stack by saving the link register?
62715995
if (OF.FrameConstructionID != MachineOutlinerDefault)
62725996
return;

0 commit comments

Comments
 (0)