Skip to content

Commit 0d9b9d1

Browse files
authored
[BOLT] Keep X86 HLT instruction as a terminator in user mode (#154402)
This is a follow-up to #150963. X86 HLT instruction may appear in the user-level code, in which case we should treat it as a terminator. Handle it as a non-terminator in the Linux kernel mode.
1 parent ec6389d commit 0d9b9d1

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

bolt/lib/Core/MCPlusBuilder.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ using namespace bolt;
3030
using namespace MCPlus;
3131

3232
namespace opts {
33+
cl::opt<bool>
34+
TerminalHLT("terminal-x86-hlt",
35+
cl::desc("Assume that execution stops at x86 HLT instruction"),
36+
cl::init(true), cl::Hidden, cl::cat(BoltCategory));
37+
3338
cl::opt<bool>
3439
TerminalTrap("terminal-trap",
3540
cl::desc("Assume that execution stops at trap instruction"),
@@ -132,10 +137,13 @@ bool MCPlusBuilder::equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B,
132137
}
133138

134139
bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
135-
return (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()) ||
136-
Analysis->isTerminator(Inst)
137-
? !isX86HLT(Inst)
138-
: false;
140+
if (isX86HLT(Inst))
141+
return opts::TerminalHLT;
142+
143+
if (Info->get(Inst.getOpcode()).isTrap())
144+
return opts::TerminalTrap;
145+
146+
return Analysis->isTerminator(Inst);
139147
}
140148

141149
void MCPlusBuilder::setTailCall(MCInst &Inst) const {

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ extern cl::opt<bool> KeepNops;
8484
extern cl::opt<bool> Lite;
8585
extern cl::list<std::string> ReorderData;
8686
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
87+
extern cl::opt<bool> TerminalHLT;
8788
extern cl::opt<bool> TerminalTrap;
8889
extern cl::opt<bool> TimeBuild;
8990
extern cl::opt<bool> TimeRewrite;
@@ -2177,7 +2178,9 @@ void RewriteInstance::adjustCommandLineOptions() {
21772178
if (!opts::KeepNops.getNumOccurrences())
21782179
opts::KeepNops = true;
21792180

2180-
// Linux kernel may resume execution after a trap instruction in some cases.
2181+
// Linux kernel may resume execution after a trap or x86 HLT instruction.
2182+
if (!opts::TerminalHLT.getNumOccurrences())
2183+
opts::TerminalHLT = false;
21812184
if (!opts::TerminalTrap.getNumOccurrences())
21822185
opts::TerminalTrap = false;
21832186
}

bolt/test/X86/cfg_build_hlt.s

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

bolt/test/X86/hlt-terminator.s

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
## Check that HLT instruction is handled differently depending on the flags.
2+
## It's a terminator in the user-level code, but the execution can resume in
3+
## ring 0.
4+
5+
# RUN: %clang %cflags %s -static -o %t.exe -nostdlib
6+
# RUN: llvm-bolt %t.exe --print-cfg --print-only=main --terminal-x86-hlt=0 \
7+
# RUN: -o %t.ring0 2>&1 | FileCheck %s --check-prefix=CHECK-RING0
8+
# RUN: llvm-bolt %t.exe --print-cfg --print-only=main \
9+
# RUN: -o %t.ring3 2>&1 | FileCheck %s --check-prefix=CHECK-RING3
10+
# RUN: llvm-objdump -d %t.ring0 --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN
11+
12+
# CHECK-RING0: BB Count : 1
13+
# CHECK-RING3: BB Count : 2
14+
15+
# CHECK-BIN: <main>:
16+
# CHECK-BIN-NEXT: f4 hlt
17+
# CHECK-BIN-NEXT: c3 retq
18+
19+
.global main
20+
.type main, %function
21+
main:
22+
hlt
23+
retq
24+
.size main, .-main

0 commit comments

Comments
 (0)