Skip to content

Commit 84ab947

Browse files
committed
[BOLT] Add allow-experimental-pacret flag
- put feature behind new flag. - to not fail because of the missing flag, read OpNegateRAState CFIs normally from binaries. - in the beginning of MarkRAStates Pass, remove all OpNegateRAState CFIs.
1 parent ef432ae commit 84ab947

File tree

5 files changed

+58
-13
lines changed

5 files changed

+58
-13
lines changed

bolt/include/bolt/Utils/CommandLineOpts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ extern llvm::cl::opt<std::string> OutputFilename;
5353
extern llvm::cl::opt<std::string> PerfData;
5454
extern llvm::cl::opt<bool> PrintCacheMetrics;
5555
extern llvm::cl::opt<bool> PrintSections;
56+
extern llvm::cl::opt<bool> AllowPacret;
5657

5758
// The format to use with -o in aggregation mode (perf2bolt)
5859
enum ProfileFormatKind { PF_Fdata, PF_YAML };

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ extern cl::opt<bool> Instrument;
6464
extern cl::opt<bool> StrictMode;
6565
extern cl::opt<bool> UpdateDebugSections;
6666
extern cl::opt<unsigned> Verbosity;
67+
extern cl::opt<bool> AllowPacret;
6768

6869
extern bool BinaryAnalysisMode;
6970
extern bool HeatmapMode;
@@ -2769,10 +2770,12 @@ struct CFISnapshot {
27692770
llvm_unreachable("unsupported CFI opcode");
27702771
break;
27712772
case MCCFIInstruction::OpNegateRAState:
2772-
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode)) {
2773-
llvm_unreachable("BOLT-ERROR: binaries using pac-ret hardening (e.g. "
2774-
"as produced by '-mbranch-protection=pac-ret') are "
2775-
"currently not supported by BOLT.");
2773+
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode ||
2774+
opts::AllowPacret)) {
2775+
llvm_unreachable(
2776+
"BOLT-ERROR: support for binaries using pac-ret hardening (e.g. as "
2777+
"produced by '-mbranch-protection=pac-ret') is experimental\n"
2778+
"BOLT-ERROR: set --allow-experimental-pacret to allow processing");
27762779
}
27772780
break;
27782781
case MCCFIInstruction::OpRememberState:
@@ -2788,7 +2791,6 @@ struct CFISnapshot {
27882791
void advanceTo(int32_t State) {
27892792
for (int32_t I = CurState, E = State; I != E; ++I) {
27902793
const MCCFIInstruction &Instr = FDE[I];
2791-
assert(Instr.getOperation() != MCCFIInstruction::OpNegateRAState);
27922794
if (Instr.getOperation() != MCCFIInstruction::OpRestoreState) {
27932795
update(Instr, I);
27942796
continue;
@@ -2916,10 +2918,12 @@ struct CFISnapshotDiff : public CFISnapshot {
29162918
llvm_unreachable("unsupported CFI opcode");
29172919
return false;
29182920
case MCCFIInstruction::OpNegateRAState:
2919-
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode)) {
2920-
llvm_unreachable("BOLT-ERROR: binaries using pac-ret hardening (e.g. "
2921-
"as produced by '-mbranch-protection=pac-ret') are "
2922-
"currently not supported by BOLT.");
2921+
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode ||
2922+
opts::AllowPacret)) {
2923+
llvm_unreachable(
2924+
"BOLT-ERROR: support for binaries using pac-ret hardening (e.g. as "
2925+
"produced by '-mbranch-protection=pac-ret') is experimental\n"
2926+
"BOLT-ERROR: set --allow-experimental-pacret to allow processing");
29232927
}
29242928
break;
29252929
case MCCFIInstruction::OpRememberState:
@@ -3073,10 +3077,12 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
30733077
llvm_unreachable("unsupported CFI opcode");
30743078
break;
30753079
case MCCFIInstruction::OpNegateRAState:
3076-
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode)) {
3077-
llvm_unreachable("BOLT-ERROR: binaries using pac-ret hardening (e.g. "
3078-
"as produced by '-mbranch-protection=pac-ret') are "
3079-
"currently not supported by BOLT.");
3080+
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode ||
3081+
opts::AllowPacret)) {
3082+
llvm_unreachable(
3083+
"BOLT-ERROR: support for binaries using pac-ret hardening (e.g. as "
3084+
"produced by '-mbranch-protection=pac-ret') is experimental\n"
3085+
"BOLT-ERROR: set --allow-experimental-pacret to allow processing");
30803086
}
30813087
break;
30823088
case MCCFIInstruction::OpGnuArgsSize:

bolt/lib/Core/Exceptions.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,14 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
650650
// the RA State. The actual state for instructions are worked out in
651651
// MarkRAStates based on these annotations.
652652
Function.setInstModifiesRAState(DW_CFA_AARCH64_negate_ra_state, Offset);
653+
// To have the --allow-experimental-pacret flag, we have to add the
654+
// OpNegateRAState CFI, and remove it later in MarkRAStates. Unittests
655+
// on AArch64 would be broken otherwise, as some AArch64 platforms will
656+
// have pac-ret for linker inserted functions, e.g.
657+
// __do_global_dtors_aux. The user cannot remove the
658+
// .cfi_negate_ra_state from such functions.
659+
Function.addCFIInstruction(
660+
Offset, MCCFIInstruction::createNegateRAState(nullptr));
653661
break;
654662
}
655663
if (opts::Verbosity >= 1)

bolt/lib/Passes/MarkRAStates.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
4343

4444
BinaryContext &BC = BF.getBinaryContext();
4545

46+
// Because of the --allow-experimental-pacret flag,
47+
// we cannot remove all OpNegateRAStates at FillCFIInfoFor,
48+
// but we still need to remove them here, because their pre-optimization
49+
// locations would be incorrect after optimizations.
50+
std::vector<BinaryBasicBlock *> Blocks(BF.pbegin(), BF.pend());
51+
for (BinaryBasicBlock *BB : Blocks) {
52+
for (auto II = BB->begin(); II != BB->end();) {
53+
MCInst &Instr = *II;
54+
if (BC.MIB->isCFI(Instr)) {
55+
const MCCFIInstruction *CFI = BF.getCFIFor(Instr);
56+
if (CFI->getOperation() == MCCFIInstruction::OpNegateRAState) {
57+
II = BB->erasePseudoInstruction(II);
58+
continue;
59+
}
60+
}
61+
++II;
62+
}
63+
}
64+
4665
for (BinaryBasicBlock &BB : BF) {
4766
for (auto It = BB.begin(); It != BB.end(); ++It) {
4867
MCInst &Inst = *It;
@@ -57,6 +76,8 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
5776
BF.setIgnored();
5877
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
5978
<< BF.getPrintName() << "\n";
79+
BC.outs()
80+
<< "BOLT-INFO: ptr sign/auth inst without .cfi_negate_ra_state\n";
6081
return;
6182
}
6283
}
@@ -77,6 +98,8 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
7798
// RA signing instructions should only follow unsigned RA state.
7899
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
79100
<< BF.getPrintName() << "\n";
101+
BC.outs() << "BOLT-INFO: ptr signing inst encountered in Signed RA "
102+
"state.\n";
80103
BF.setIgnored();
81104
return;
82105
}
@@ -86,6 +109,8 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
86109
// RA authenticating instructions should only follow signed RA state.
87110
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
88111
<< BF.getPrintName() << "\n";
112+
BC.outs() << "BOLT-INFO: ptr authenticating inst encountered in "
113+
"Unsigned RA state.\n";
89114
BF.setIgnored();
90115
return;
91116
}

bolt/lib/Rewrite/BinaryPassManager.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,11 @@ static cl::opt<bool> ShortenInstructions("shorten-instructions",
275275
cl::desc("shorten instructions"),
276276
cl::init(true),
277277
cl::cat(BoltOptCategory));
278+
279+
cl::opt<bool> AllowPacret(
280+
"allow-experimental-pacret",
281+
cl::desc("Enable processing binaries with pac-ret (experimental)"),
282+
cl::cat(BoltOptCategory));
278283
} // namespace opts
279284

280285
namespace llvm {

0 commit comments

Comments
 (0)