Skip to content

Commit 7de82ca

Browse files
authored
[BOLT] Don't terminate on trap instruction for Linux kernel (#87021)
Under normal circumstances, we terminate basic blocks on a trap instruction. However, Linux kernel may resume execution after hitting a trap (ud2 on x86). Thus, we introduce "--terminal-trap" option that will specify if the trap instruction should terminate the control flow. The option is on by default except for the Linux kernel mode when it's off.
1 parent 7467dc1 commit 7de82ca

File tree

5 files changed

+28
-12
lines changed

5 files changed

+28
-12
lines changed

bolt/include/bolt/Core/MCPlusBuilder.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -533,9 +533,7 @@ class MCPlusBuilder {
533533
return Analysis->isReturn(Inst);
534534
}
535535

536-
virtual bool isTerminator(const MCInst &Inst) const {
537-
return Analysis->isTerminator(Inst);
538-
}
536+
virtual bool isTerminator(const MCInst &Inst) const;
539537

540538
virtual bool isNoop(const MCInst &Inst) const {
541539
llvm_unreachable("not implemented");

bolt/lib/Core/MCPlusBuilder.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212

1313
#include "bolt/Core/MCPlusBuilder.h"
1414
#include "bolt/Core/MCPlus.h"
15+
#include "bolt/Utils/CommandLineOpts.h"
1516
#include "llvm/MC/MCContext.h"
1617
#include "llvm/MC/MCInst.h"
1718
#include "llvm/MC/MCInstrAnalysis.h"
1819
#include "llvm/MC/MCInstrDesc.h"
1920
#include "llvm/MC/MCInstrInfo.h"
2021
#include "llvm/MC/MCRegisterInfo.h"
22+
#include "llvm/Support/CommandLine.h"
2123
#include "llvm/Support/Debug.h"
2224
#include <cstdint>
2325
#include <queue>
@@ -28,6 +30,13 @@ using namespace llvm;
2830
using namespace bolt;
2931
using namespace MCPlus;
3032

33+
namespace opts {
34+
cl::opt<bool>
35+
TerminalTrap("terminal-trap",
36+
cl::desc("Assume that execution stops at trap instruction"),
37+
cl::init(true), cl::Hidden, cl::cat(BoltCategory));
38+
}
39+
3140
bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B,
3241
CompFuncTy Comp) const {
3342
if (A.getOpcode() != B.getOpcode())
@@ -121,6 +130,11 @@ bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B,
121130
llvm_unreachable("target-specific expressions are unsupported");
122131
}
123132

133+
bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
134+
return Analysis->isTerminator(Inst) ||
135+
(opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap());
136+
}
137+
124138
void MCPlusBuilder::setTailCall(MCInst &Inst) const {
125139
assert(!hasAnnotation(Inst, MCAnnotation::kTailCall));
126140
setAnnotationOpValue(Inst, MCAnnotation::kTailCall, true);

bolt/lib/Rewrite/RewriteInstance.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ extern cl::opt<JumpTableSupportLevel> JumpTables;
8484
extern cl::opt<bool> KeepNops;
8585
extern cl::list<std::string> ReorderData;
8686
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
87+
extern cl::opt<bool> TerminalTrap;
8788
extern cl::opt<bool> TimeBuild;
8889

8990
cl::opt<bool> AllowStripped("allow-stripped",
@@ -2033,8 +2034,14 @@ void RewriteInstance::adjustCommandLineOptions() {
20332034
if (opts::Lite)
20342035
BC->outs() << "BOLT-INFO: enabling lite mode\n";
20352036

2036-
if (BC->IsLinuxKernel && !opts::KeepNops.getNumOccurrences())
2037-
opts::KeepNops = true;
2037+
if (BC->IsLinuxKernel) {
2038+
if (!opts::KeepNops.getNumOccurrences())
2039+
opts::KeepNops = true;
2040+
2041+
// Linux kernel may resume execution after a trap instruction in some cases.
2042+
if (!opts::TerminalTrap.getNumOccurrences())
2043+
opts::TerminalTrap = false;
2044+
}
20382045
}
20392046

20402047
namespace {

bolt/lib/Target/X86/X86MCPlusBuilder.cpp

-7
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,6 @@ class X86MCPlusBuilder : public MCPlusBuilder {
211211
return false;
212212
}
213213

214-
// FIXME: For compatibility with old LLVM only!
215-
bool isTerminator(const MCInst &Inst) const override {
216-
unsigned Opcode = Inst.getOpcode();
217-
return Info->get(Opcode).isTerminator() || X86::isUD1(Opcode) ||
218-
X86::isUD2(Opcode);
219-
}
220-
221214
bool isIndirectCall(const MCInst &Inst) const override {
222215
return isCall(Inst) &&
223216
((getMemoryOperandNo(Inst) != -1) || Inst.getOperand(0).isReg());

bolt/test/X86/linux-bug-table.s

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ _start:
4040
# CHECK-REOPT-SAME: BugEntry: 2
4141

4242
ret
43+
## The return instruction is reachable only via preceding ud2. Test that it is
44+
## treated as a reachable instruction in the Linux kernel mode.
45+
46+
# CHECK-REOPT-NEXT: ret
4347
.size _start, .-_start
4448

4549

0 commit comments

Comments
 (0)