Skip to content

Commit a3f4745

Browse files
committed
Revert "[AArch64][MachineOutliner] Return address signing for outlined functions"
This is causing faults when an instruction which modifies SP is outlined, causing the PAC and AUT instructions to not match. This reverts commits 70caa1f and 55314d3.
1 parent 6e759da commit a3f4745

10 files changed

+7
-966
lines changed

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 7 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,147 +5037,15 @@ AArch64InstrInfo::findRegisterToSaveLRTo(const outliner::Candidate &C) const {
50375037
return 0u;
50385038
}
50395039

5040-
static bool
5041-
outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a,
5042-
const outliner::Candidate &b) {
5043-
const Function &Fa = a.getMF()->getFunction();
5044-
const Function &Fb = b.getMF()->getFunction();
5045-
5046-
// If none of the functions have the "sign-return-address" attribute their
5047-
// signing behaviour is equal
5048-
if (!Fa.hasFnAttribute("sign-return-address") &&
5049-
!Fb.hasFnAttribute("sign-return-address")) {
5050-
return true;
5051-
}
5052-
5053-
// If both functions have the "sign-return-address" attribute their signing
5054-
// behaviour is equal, if the values of the attributes are equal
5055-
if (Fa.hasFnAttribute("sign-return-address") &&
5056-
Fb.hasFnAttribute("sign-return-address")) {
5057-
StringRef ScopeA =
5058-
Fa.getFnAttribute("sign-return-address").getValueAsString();
5059-
StringRef ScopeB =
5060-
Fb.getFnAttribute("sign-return-address").getValueAsString();
5061-
return ScopeA.equals(ScopeB);
5062-
}
5063-
5064-
// If function B doesn't have the "sign-return-address" attribute but A does,
5065-
// the functions' signing behaviour is equal if A's value for
5066-
// "sign-return-address" is "none" and vice versa.
5067-
if (Fa.hasFnAttribute("sign-return-address")) {
5068-
StringRef ScopeA =
5069-
Fa.getFnAttribute("sign-return-address").getValueAsString();
5070-
return ScopeA.equals("none");
5071-
}
5072-
5073-
if (Fb.hasFnAttribute("sign-return-address")) {
5074-
StringRef ScopeB =
5075-
Fb.getFnAttribute("sign-return-address").getValueAsString();
5076-
return ScopeB.equals("none");
5077-
}
5078-
5079-
llvm_unreachable("Unkown combination of sign-return-address attributes");
5080-
}
5081-
5082-
static bool
5083-
outliningCandidatesSigningKeyConsensus(const outliner::Candidate &a,
5084-
const outliner::Candidate &b) {
5085-
const Function &Fa = a.getMF()->getFunction();
5086-
const Function &Fb = b.getMF()->getFunction();
5087-
5088-
// If none of the functions have the "sign-return-address-key" attribute
5089-
// their keys are equal
5090-
if (!Fa.hasFnAttribute("sign-return-address-key") &&
5091-
!Fb.hasFnAttribute("sign-return-address-key")) {
5092-
return true;
5093-
}
5094-
5095-
// If both functions have the "sign-return-address-key" attribute their
5096-
// keys are equal if the values of "sign-return-address-key" are equal
5097-
if (Fa.hasFnAttribute("sign-return-address-key") &&
5098-
Fb.hasFnAttribute("sign-return-address-key")) {
5099-
StringRef KeyA =
5100-
Fa.getFnAttribute("sign-return-address-key").getValueAsString();
5101-
StringRef KeyB =
5102-
Fb.getFnAttribute("sign-return-address-key").getValueAsString();
5103-
return KeyA.equals(KeyB);
5104-
}
5105-
5106-
// If B doesn't have the "sign-return-address-key" attribute, both keys are
5107-
// equal, if function a has the default key (a_key)
5108-
if (Fa.hasFnAttribute("sign-return-address-key")) {
5109-
StringRef KeyA =
5110-
Fa.getFnAttribute("sign-return-address-key").getValueAsString();
5111-
return KeyA.equals_lower("a_key");
5112-
}
5113-
5114-
if (Fb.hasFnAttribute("sign-return-address-key")) {
5115-
StringRef KeyB =
5116-
Fb.getFnAttribute("sign-return-address-key").getValueAsString();
5117-
return KeyB.equals_lower("a_key");
5118-
}
5119-
5120-
llvm_unreachable("Unkown combination of sign-return-address-key attributes");
5121-
}
5122-
5123-
static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a,
5124-
const outliner::Candidate &b) {
5125-
const AArch64Subtarget &SubtargetA =
5126-
a.getMF()->getSubtarget<AArch64Subtarget>();
5127-
const AArch64Subtarget &SubtargetB =
5128-
b.getMF()->getSubtarget<AArch64Subtarget>();
5129-
return SubtargetA.hasV8_3aOps() == SubtargetB.hasV8_3aOps();
5130-
}
5131-
5132-
outliner::OutlinedFunction AArch64InstrInfo::getOutliningCandidateInfo(
5040+
outliner::OutlinedFunction
5041+
AArch64InstrInfo::getOutliningCandidateInfo(
51335042
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
51345043
outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
51355044
unsigned SequenceSize =
51365045
std::accumulate(FirstCand.front(), std::next(FirstCand.back()), 0,
51375046
[this](unsigned Sum, const MachineInstr &MI) {
51385047
return Sum + getInstSizeInBytes(MI);
51395048
});
5140-
unsigned NumBytesToCreateFrame = 0;
5141-
5142-
// We only allow outlining for functions having exactly matching return
5143-
// address signing attributes, i.e., all share the same value for the
5144-
// attribute "sign-return-address" and all share the same type of key they
5145-
// are signed with.
5146-
// Additionally we require all functions to simultaniously either support
5147-
// v8.3a features or not. Otherwise an outlined function could get signed
5148-
// using dedicated v8.3 instructions and a call from a function that doesn't
5149-
// support v8.3 instructions would therefore be invalid.
5150-
if (std::adjacent_find(
5151-
RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
5152-
5153-
[](const outliner::Candidate &a, const outliner::Candidate &b) {
5154-
// Return true if a and b are non-equal w.r.t. return address
5155-
// signing or support of v8.3a features
5156-
if (outliningCandidatesSigningScopeConsensus(a, b) &&
5157-
outliningCandidatesSigningKeyConsensus(a, b) &&
5158-
outliningCandidatesV8_3OpsConsensus(a, b)) {
5159-
return false;
5160-
}
5161-
return true;
5162-
}) != RepeatedSequenceLocs.end()) {
5163-
return outliner::OutlinedFunction();
5164-
}
5165-
5166-
// Since at this point all candidates agree on their return address signing
5167-
// picking just one is fine. If the candidate functions potentially sign their
5168-
// return addresses, the outlined function should do the same. Note that in
5169-
// the case of "sign-return-address"="non-leaf" this is an assumption: It is
5170-
// not certainly true that the outlined function will have to sign its return
5171-
// address but this decision is made later, when the decision to outline
5172-
// has already been made.
5173-
// The same holds for the number of additional instructions we need: On
5174-
// v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is
5175-
// necessary. However, at this point we don't know if the outlined function
5176-
// will have a RET instruction so we assume the worst.
5177-
const Function &FCF = FirstCand.getMF()->getFunction();
5178-
if (FCF.hasFnAttribute("sign-return-address"))
5179-
// One PAC and one AUT instructions
5180-
NumBytesToCreateFrame += 8;
51815049

51825050
// Properties about candidate MBBs that hold for all of them.
51835051
unsigned FlagsSetInAll = 0xF;
@@ -5239,7 +5107,7 @@ outliner::OutlinedFunction AArch64InstrInfo::getOutliningCandidateInfo(
52395107
};
52405108

52415109
unsigned FrameID = MachineOutlinerDefault;
5242-
NumBytesToCreateFrame += 4;
5110+
unsigned NumBytesToCreateFrame = 4;
52435111

52445112
bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
52455113
return C.getMF()->getFunction().hasFnAttribute("branch-target-enforcement");
@@ -5508,19 +5376,6 @@ AArch64InstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
55085376
MachineFunction *MF = MBB->getParent();
55095377
AArch64FunctionInfo *FuncInfo = MF->getInfo<AArch64FunctionInfo>();
55105378

5511-
// Don't outline anything used for return address signing. The outlined
5512-
// function will get signed later if needed
5513-
switch (MI.getOpcode()) {
5514-
case AArch64::PACIASP:
5515-
case AArch64::PACIBSP:
5516-
case AArch64::AUTIASP:
5517-
case AArch64::AUTIBSP:
5518-
case AArch64::RETAA:
5519-
case AArch64::RETAB:
5520-
case AArch64::EMITBKEY:
5521-
return outliner::InstrType::Illegal;
5522-
}
5523-
55245379
// Don't outline LOHs.
55255380
if (FuncInfo->getLOHRelated().count(&MI))
55265381
return outliner::InstrType::Illegal;
@@ -5673,59 +5528,6 @@ void AArch64InstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
56735528
}
56745529
}
56755530

5676-
static void signOutlinedFunction(MachineFunction &MF, MachineBasicBlock &MBB,
5677-
bool ShouldSignReturnAddr,
5678-
bool ShouldSignReturnAddrWithAKey) {
5679-
if (ShouldSignReturnAddr) {
5680-
MachineBasicBlock::iterator MBBPAC = MBB.begin();
5681-
MachineBasicBlock::iterator MBBAUT = MBB.getFirstTerminator();
5682-
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
5683-
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
5684-
DebugLoc DL;
5685-
5686-
if (MBBAUT != MBB.end())
5687-
DL = MBBAUT->getDebugLoc();
5688-
5689-
// At the very beginning of the basic block we insert the following
5690-
// depending on the key type
5691-
//
5692-
// a_key: b_key:
5693-
// PACIASP EMITBKEY
5694-
// CFI_INSTRUCTION PACIBSP
5695-
// CFI_INSTRUCTION
5696-
if (ShouldSignReturnAddrWithAKey) {
5697-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::PACIASP))
5698-
.setMIFlag(MachineInstr::FrameSetup);
5699-
} else {
5700-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::EMITBKEY))
5701-
.setMIFlag(MachineInstr::FrameSetup);
5702-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::PACIBSP))
5703-
.setMIFlag(MachineInstr::FrameSetup);
5704-
}
5705-
unsigned CFIIndex =
5706-
MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
5707-
BuildMI(MBB, MBBPAC, DebugLoc(), TII->get(AArch64::CFI_INSTRUCTION))
5708-
.addCFIIndex(CFIIndex)
5709-
.setMIFlags(MachineInstr::FrameSetup);
5710-
5711-
// If v8.3a features are available we can replace a RET instruction by
5712-
// RETAA or RETAB and omit the AUT instructions
5713-
if (Subtarget.hasV8_3aOps() && MBBAUT != MBB.end() &&
5714-
MBBAUT->getOpcode() == AArch64::RET) {
5715-
BuildMI(MBB, MBBAUT, DL,
5716-
TII->get(ShouldSignReturnAddrWithAKey ? AArch64::RETAA
5717-
: AArch64::RETAB))
5718-
.copyImplicitOps(*MBBAUT);
5719-
MBB.erase(MBBAUT);
5720-
} else {
5721-
BuildMI(MBB, MBBAUT, DL,
5722-
TII->get(ShouldSignReturnAddrWithAKey ? AArch64::AUTIASP
5723-
: AArch64::AUTIBSP))
5724-
.setMIFlag(MachineInstr::FrameDestroy);
5725-
}
5726-
}
5727-
}
5728-
57295531
void AArch64InstrInfo::buildOutlinedFrame(
57305532
MachineBasicBlock &MBB, MachineFunction &MF,
57315533
const outliner::OutlinedFunction &OF) const {
@@ -5741,28 +5543,23 @@ void AArch64InstrInfo::buildOutlinedFrame(
57415543
TailOpcode = AArch64::TCRETURNriALL;
57425544
}
57435545
MachineInstr *TC = BuildMI(MF, DebugLoc(), get(TailOpcode))
5744-
.add(Call->getOperand(0))
5745-
.addImm(0);
5546+
.add(Call->getOperand(0))
5547+
.addImm(0);
57465548
MBB.insert(MBB.end(), TC);
57475549
Call->eraseFromParent();
57485550
}
57495551

5750-
bool IsLeafFunction = true;
5751-
57525552
// Is there a call in the outlined range?
5753-
auto IsNonTailCall = [](const MachineInstr &MI) {
5553+
auto IsNonTailCall = [](MachineInstr &MI) {
57545554
return MI.isCall() && !MI.isReturn();
57555555
};
5756-
57575556
if (std::any_of(MBB.instr_begin(), MBB.instr_end(), IsNonTailCall)) {
57585557
// Fix up the instructions in the range, since we're going to modify the
57595558
// stack.
57605559
assert(OF.FrameConstructionID != MachineOutlinerDefault &&
57615560
"Can only fix up stack references once");
57625561
fixupPostOutline(MBB);
57635562

5764-
IsLeafFunction = false;
5765-
57665563
// LR has to be a live in so that we can save it.
57675564
MBB.addLiveIn(AArch64::LR);
57685565

@@ -5809,47 +5606,16 @@ void AArch64InstrInfo::buildOutlinedFrame(
58095606
Et = MBB.insert(Et, LDRXpost);
58105607
}
58115608

5812-
// If a bunch of candidates reach this point they must agree on their return
5813-
// address signing. It is therefore enough to just consider the signing
5814-
// behaviour of one of them
5815-
const Function &CF = OF.Candidates.front().getMF()->getFunction();
5816-
bool ShouldSignReturnAddr = false;
5817-
if (CF.hasFnAttribute("sign-return-address")) {
5818-
StringRef Scope =
5819-
CF.getFnAttribute("sign-return-address").getValueAsString();
5820-
if (Scope.equals("all"))
5821-
ShouldSignReturnAddr = true;
5822-
else if (Scope.equals("non-leaf") && !IsLeafFunction)
5823-
ShouldSignReturnAddr = true;
5824-
}
5825-
5826-
// a_key is the default
5827-
bool ShouldSignReturnAddrWithAKey = true;
5828-
if (CF.hasFnAttribute("sign-return-address-key")) {
5829-
const StringRef Key =
5830-
CF.getFnAttribute("sign-return-address-key").getValueAsString();
5831-
// Key can either be a_key or b_key
5832-
assert((Key.equals_lower("a_key") || Key.equals_lower("b_key")) &&
5833-
"Return address signing key must be either a_key or b_key");
5834-
ShouldSignReturnAddrWithAKey = Key.equals_lower("a_key");
5835-
}
5836-
58375609
// If this is a tail call outlined function, then there's already a return.
58385610
if (OF.FrameConstructionID == MachineOutlinerTailCall ||
5839-
OF.FrameConstructionID == MachineOutlinerThunk) {
5840-
signOutlinedFunction(MF, MBB, ShouldSignReturnAddr,
5841-
ShouldSignReturnAddrWithAKey);
5611+
OF.FrameConstructionID == MachineOutlinerThunk)
58425612
return;
5843-
}
58445613

58455614
// It's not a tail call, so we have to insert the return ourselves.
58465615
MachineInstr *ret = BuildMI(MF, DebugLoc(), get(AArch64::RET))
58475616
.addReg(AArch64::LR, RegState::Undef);
58485617
MBB.insert(MBB.end(), ret);
58495618

5850-
signOutlinedFunction(MF, MBB, ShouldSignReturnAddr,
5851-
ShouldSignReturnAddrWithAKey);
5852-
58535619
// Did we have to modify the stack by saving the link register?
58545620
if (OF.FrameConstructionID != MachineOutlinerDefault)
58555621
return;

llvm/test/CodeGen/AArch64/machine-outliner-retaddr-sign-diff-scope-same-key.ll

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)