Skip to content

Commit 7df2811

Browse files
committed
[BOLT] Refactor and improve InsertNegateRAStatePass
- separate function splitting code into its own function - change the iteration looking for state-switches between consecutive instructions to only look for changes *inside* FunctionFragments, and skip borders between them.
1 parent 4a976a4 commit 7df2811

File tree

2 files changed

+53
-45
lines changed

2 files changed

+53
-45
lines changed

bolt/include/bolt/Passes/InsertNegateRAStatePass.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ class InsertNegateRAState : public BinaryFunctionPass {
4141
/// newly inserted instructions do not have a state associated with them.
4242
/// New states are "inherited" from the last known state.
4343
void inferUnknownStates(BinaryFunction &BF);
44+
45+
/// Support for function splitting:
46+
/// if two consecutive BBs with Signed state are going to end up in different
47+
/// functions (so are held by different FunctionFragments), we have to add a
48+
/// OpNegateRAState to the beginning of the newly split function, so it starts
49+
/// with a Signed state.
50+
void coverFunctionFragmentStart(BinaryFunction &BF, FunctionFragment &FF);
4451
};
4552

4653
} // namespace bolt

bolt/lib/Passes/InsertNegateRAStatePass.cpp

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -34,57 +34,35 @@ void InsertNegateRAState::runOnFunction(BinaryFunction &BF) {
3434
return;
3535
}
3636

37-
// If none is inserted, the function doesn't need more work.
38-
if (!addNegateRAStateAfterPSignOrPAuth(BF))
39-
return;
37+
// Attach .cfi_negate_ra_state to the "trivial" cases first.
38+
addNegateRAStateAfterPSignOrPAuth(BF);
4039

4140
inferUnknownStates(BF);
4241

43-
// Support for function splitting:
44-
// if two consecutive BBs with Signed state are going to end up in different
45-
// functions (so are held by different FunctionFragments), we have to add a
46-
// OpNegateRAState to the beginning of the newly split function, so it starts
47-
// with a Signed state.
4842
for (FunctionFragment &FF : BF.getLayout().fragments()) {
49-
// Find the first BB in the FF which has Instructions.
50-
// BOLT can generate empty BBs at function splitting which are only used as
51-
// target labels. We should add the negate-ra-state CFI to the first
52-
// non-empty BB.
53-
auto *FirstNonEmpty =
54-
std::find_if(FF.begin(), FF.end(), [](BinaryBasicBlock *BB) {
55-
// getFirstNonPseudo returns BB.end() if it does not find any
56-
// Instructions.
57-
return BB->getFirstNonPseudo() != BB->end();
58-
});
59-
if (BC.MIB->isRASigned(*((*FirstNonEmpty)->begin()))) {
60-
BF.addCFIInstruction(*FirstNonEmpty, (*FirstNonEmpty)->begin(),
61-
MCCFIInstruction::createNegateRAState(nullptr));
62-
}
63-
}
64-
65-
bool FirstIter = true;
66-
MCInst PrevInst;
67-
for (BinaryBasicBlock &BB : BF) {
68-
for (auto It = BB.begin(); It != BB.end(); ++It) {
69-
70-
MCInst &Inst = *It;
71-
if (BC.MIB->isCFI(Inst))
72-
continue;
73-
74-
if (!FirstIter) {
75-
// Consecutive instructions with different RAState means we need to add
76-
// a OpNegateRAState.
77-
if ((BC.MIB->isRASigned(PrevInst) && BC.MIB->isRAUnsigned(Inst)) ||
78-
(BC.MIB->isRAUnsigned(PrevInst) && BC.MIB->isRASigned(Inst))) {
79-
80-
It = BF.addCFIInstruction(
81-
&BB, It, MCCFIInstruction::createNegateRAState(nullptr));
43+
coverFunctionFragmentStart(BF, FF);
44+
bool FirstIter = true;
45+
MCInst PrevInst;
46+
// As this pass runs after function splitting, we should only check
47+
// consecutive instructions inside FunctionFragments.
48+
for (BinaryBasicBlock *BB : FF) {
49+
for (auto It = BB->begin(); It != BB->end(); ++It) {
50+
MCInst &Inst = *It;
51+
if (BC.MIB->isCFI(Inst))
52+
continue;
53+
if (!FirstIter) {
54+
// Consecutive instructions with different RAState means we need to
55+
// add a OpNegateRAState.
56+
if ((BC.MIB->isRASigned(PrevInst) && BC.MIB->isRAUnsigned(Inst)) ||
57+
(BC.MIB->isRAUnsigned(PrevInst) && BC.MIB->isRASigned(Inst))) {
58+
It = BF.addCFIInstruction(
59+
BB, It, MCCFIInstruction::createNegateRAState(nullptr));
60+
}
61+
} else {
62+
FirstIter = false;
8263
}
83-
84-
} else {
85-
FirstIter = false;
64+
PrevInst = *It;
8665
}
87-
PrevInst = *It;
8866
}
8967
}
9068
}
@@ -107,6 +85,29 @@ bool InsertNegateRAState::addNegateRAStateAfterPSignOrPAuth(
10785
return FoundAny;
10886
}
10987

88+
void InsertNegateRAState::coverFunctionFragmentStart(BinaryFunction &BF,
89+
FunctionFragment &FF) {
90+
BinaryContext &BC = BF.getBinaryContext();
91+
if (FF.empty())
92+
return;
93+
// Find the first BB in the FF which has Instructions.
94+
// BOLT can generate empty BBs at function splitting which are only used as
95+
// target labels. We should add the negate-ra-state CFI to the first
96+
// non-empty BB.
97+
auto *FirstNonEmpty =
98+
std::find_if(FF.begin(), FF.end(), [](BinaryBasicBlock *BB) {
99+
// getFirstNonPseudo returns BB.end() if it does not find any
100+
// Instructions.
101+
return BB->getFirstNonPseudo() != BB->end();
102+
});
103+
// If a function is already split in the input, the first FF can also start
104+
// with Signed state. This covers that scenario as well.
105+
if (BC.MIB->isRASigned(*((*FirstNonEmpty)->begin()))) {
106+
BF.addCFIInstruction(*FirstNonEmpty, (*FirstNonEmpty)->begin(),
107+
MCCFIInstruction::createNegateRAState(nullptr));
108+
}
109+
}
110+
110111
void InsertNegateRAState::inferUnknownStates(BinaryFunction &BF) {
111112
BinaryContext &BC = BF.getBinaryContext();
112113
bool FirstIter = true;

0 commit comments

Comments
 (0)