Skip to content

Commit 938fc4e

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 e288d64 commit 938fc4e

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
@@ -72,6 +72,7 @@ extern llvm::cl::opt<std::string> OutputFilename;
7272
extern llvm::cl::opt<std::string> PerfData;
7373
extern llvm::cl::opt<bool> PrintCacheMetrics;
7474
extern llvm::cl::opt<bool> PrintSections;
75+
extern llvm::cl::opt<bool> AllowPacret;
7576

7677
// The format to use with -o in aggregation mode (perf2bolt)
7778
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 HeatmapModeKind HeatmapMode;
@@ -2785,10 +2786,12 @@ struct CFISnapshot {
27852786
llvm_unreachable("unsupported CFI opcode");
27862787
break;
27872788
case MCCFIInstruction::OpNegateRAState:
2788-
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode)) {
2789-
llvm_unreachable("BOLT-ERROR: binaries using pac-ret hardening (e.g. "
2790-
"as produced by '-mbranch-protection=pac-ret') are "
2791-
"currently not supported by BOLT.");
2789+
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode ||
2790+
opts::AllowPacret)) {
2791+
llvm_unreachable(
2792+
"BOLT-ERROR: support for binaries using pac-ret hardening (e.g. as "
2793+
"produced by '-mbranch-protection=pac-ret') is experimental\n"
2794+
"BOLT-ERROR: set --allow-experimental-pacret to allow processing");
27922795
}
27932796
break;
27942797
case MCCFIInstruction::OpRememberState:
@@ -2804,7 +2807,6 @@ struct CFISnapshot {
28042807
void advanceTo(int32_t State) {
28052808
for (int32_t I = CurState, E = State; I != E; ++I) {
28062809
const MCCFIInstruction &Instr = FDE[I];
2807-
assert(Instr.getOperation() != MCCFIInstruction::OpNegateRAState);
28082810
if (Instr.getOperation() != MCCFIInstruction::OpRestoreState) {
28092811
update(Instr, I);
28102812
continue;
@@ -2932,10 +2934,12 @@ struct CFISnapshotDiff : public CFISnapshot {
29322934
llvm_unreachable("unsupported CFI opcode");
29332935
return false;
29342936
case MCCFIInstruction::OpNegateRAState:
2935-
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode)) {
2936-
llvm_unreachable("BOLT-ERROR: binaries using pac-ret hardening (e.g. "
2937-
"as produced by '-mbranch-protection=pac-ret') are "
2938-
"currently not supported by BOLT.");
2937+
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode ||
2938+
opts::AllowPacret)) {
2939+
llvm_unreachable(
2940+
"BOLT-ERROR: support for binaries using pac-ret hardening (e.g. as "
2941+
"produced by '-mbranch-protection=pac-ret') is experimental\n"
2942+
"BOLT-ERROR: set --allow-experimental-pacret to allow processing");
29392943
}
29402944
break;
29412945
case MCCFIInstruction::OpRememberState:
@@ -3089,10 +3093,12 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
30893093
llvm_unreachable("unsupported CFI opcode");
30903094
break;
30913095
case MCCFIInstruction::OpNegateRAState:
3092-
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode)) {
3093-
llvm_unreachable("BOLT-ERROR: binaries using pac-ret hardening (e.g. "
3094-
"as produced by '-mbranch-protection=pac-ret') are "
3095-
"currently not supported by BOLT.");
3096+
if (!(opts::BinaryAnalysisMode || opts::HeatmapMode ||
3097+
opts::AllowPacret)) {
3098+
llvm_unreachable(
3099+
"BOLT-ERROR: support for binaries using pac-ret hardening (e.g. as "
3100+
"produced by '-mbranch-protection=pac-ret') is experimental\n"
3101+
"BOLT-ERROR: set --allow-experimental-pacret to allow processing");
30963102
}
30973103
break;
30983104
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)