Skip to content

Commit 71e8021

Browse files
scottconstabletopperc
authored andcommitted
[X86][NFC] Generalize the naming of "Retpoline Thunks" and related code to "Indirect Thunks"
There are applications for indirect call/branch thunks other than retpoline for Spectre v2, e.g., https://software.intel.com/security-software-guidance/software-guidance/load-value-injection Therefore it makes sense to refactor X86RetpolineThunks as a more general capability. Differential Revision: https://reviews.llvm.org/D76810
1 parent 31b6e18 commit 71e8021

16 files changed

+137
-115
lines changed

llvm/lib/Target/X86/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ set(sources
4444
X86ISelDAGToDAG.cpp
4545
X86ISelLowering.cpp
4646
X86IndirectBranchTracking.cpp
47+
X86IndirectThunks.cpp
4748
X86InterleavedAccess.cpp
4849
X86InsertPrefetch.cpp
4950
X86InstrFMA3Info.cpp
@@ -59,7 +60,6 @@ set(sources
5960
X86PartialReduction.cpp
6061
X86RegisterBankInfo.cpp
6162
X86RegisterInfo.cpp
62-
X86RetpolineThunks.cpp
6363
X86SelectionDAGInfo.cpp
6464
X86ShuffleDecodeConstantPool.cpp
6565
X86SpeculativeLoadHardening.cpp

llvm/lib/Target/X86/X86.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ FunctionPass *createX86DomainReassignmentPass();
120120
FunctionPass *createX86EvexToVexInsts();
121121

122122
/// This pass creates the thunks for the retpoline feature.
123-
FunctionPass *createX86RetpolineThunksPass();
123+
FunctionPass *createX86IndirectThunksPass();
124124

125125
/// This pass ensures instructions featuring a memory operand
126126
/// have distinctive <LineNumber, Discriminator> (with respect to eachother)

llvm/lib/Target/X86/X86FastISel.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3207,8 +3207,8 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
32073207
(CalledFn && CalledFn->hasFnAttribute("no_caller_saved_registers")))
32083208
return false;
32093209

3210-
// Functions using retpoline for indirect calls need to use SDISel.
3211-
if (Subtarget->useRetpolineIndirectCalls())
3210+
// Functions using thunks for indirect calls need to use SDISel.
3211+
if (Subtarget->useIndirectThunkCalls())
32123212
return false;
32133213

32143214
// Handle only C, fastcc, and webkit_js calling conventions for now.

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -956,10 +956,10 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
956956
bool InProlog) const {
957957
bool IsLargeCodeModel = MF.getTarget().getCodeModel() == CodeModel::Large;
958958

959-
// FIXME: Add retpoline support and remove this.
960-
if (Is64Bit && IsLargeCodeModel && STI.useRetpolineIndirectCalls())
959+
// FIXME: Add indirect thunk support and remove this.
960+
if (Is64Bit && IsLargeCodeModel && STI.useIndirectThunkCalls())
961961
report_fatal_error("Emitting stack probe calls on 64-bit with the large "
962-
"code model and retpoline not yet implemented.");
962+
"code model and indirect thunks not yet implemented.");
963963

964964
unsigned CallOp;
965965
if (Is64Bit)
@@ -2683,9 +2683,9 @@ void X86FrameLowering::adjustForSegmentedStacks(
26832683
// is laid out within 2^31 bytes of each function body, but this seems
26842684
// to be sufficient for JIT.
26852685
// FIXME: Add retpoline support and remove the error here..
2686-
if (STI.useRetpolineIndirectCalls())
2686+
if (STI.useIndirectThunkCalls())
26872687
report_fatal_error("Emitting morestack calls on 64-bit with the large "
2688-
"code model and retpoline not yet implemented.");
2688+
"code model and thunks not yet implemented.");
26892689
BuildMI(allocMBB, DL, TII.get(X86::CALL64m))
26902690
.addReg(X86::RIP)
26912691
.addImm(0)

llvm/lib/Target/X86/X86ISelDAGToDAG.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ void X86DAGToDAGISel::PreprocessISelDAG() {
10391039
if (OptLevel != CodeGenOpt::None &&
10401040
// Only do this when the target can fold the load into the call or
10411041
// jmp.
1042-
!Subtarget->useRetpolineIndirectCalls() &&
1042+
!Subtarget->useIndirectThunkCalls() &&
10431043
((N->getOpcode() == X86ISD::CALL && !Subtarget->slowTwoMemOps()) ||
10441044
(N->getOpcode() == X86ISD::TC_RETURN &&
10451045
(Subtarget->is64Bit() ||

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30696,8 +30696,8 @@ bool X86TargetLowering::isVectorClearMaskLegal(ArrayRef<int> Mask,
3069630696
}
3069730697

3069830698
bool X86TargetLowering::areJTsAllowed(const Function *Fn) const {
30699-
// If the subtarget is using retpolines, we need to not generate jump tables.
30700-
if (Subtarget.useRetpolineIndirectBranches())
30699+
// If the subtarget is using thunks, we need to not generate jump tables.
30700+
if (Subtarget.useIndirectThunkBranches())
3070130701
return false;
3070230702

3070330703
// Otherwise, fallback on the generic logic.
@@ -31900,22 +31900,22 @@ X86TargetLowering::EmitLoweredTLSCall(MachineInstr &MI,
3190031900
return BB;
3190131901
}
3190231902

31903-
static unsigned getOpcodeForRetpoline(unsigned RPOpc) {
31903+
static unsigned getOpcodeForIndirectThunk(unsigned RPOpc) {
3190431904
switch (RPOpc) {
31905-
case X86::RETPOLINE_CALL32:
31905+
case X86::INDIRECT_THUNK_CALL32:
3190631906
return X86::CALLpcrel32;
31907-
case X86::RETPOLINE_CALL64:
31907+
case X86::INDIRECT_THUNK_CALL64:
3190831908
return X86::CALL64pcrel32;
31909-
case X86::RETPOLINE_TCRETURN32:
31909+
case X86::INDIRECT_THUNK_TCRETURN32:
3191031910
return X86::TCRETURNdi;
31911-
case X86::RETPOLINE_TCRETURN64:
31911+
case X86::INDIRECT_THUNK_TCRETURN64:
3191231912
return X86::TCRETURNdi64;
3191331913
}
31914-
llvm_unreachable("not retpoline opcode");
31914+
llvm_unreachable("not indirect thunk opcode");
3191531915
}
3191631916

31917-
static const char *getRetpolineSymbol(const X86Subtarget &Subtarget,
31918-
unsigned Reg) {
31917+
static const char *getIndirectThunkSymbol(const X86Subtarget &Subtarget,
31918+
unsigned Reg) {
3191931919
if (Subtarget.useRetpolineExternalThunk()) {
3192031920
// When using an external thunk for retpolines, we pick names that match the
3192131921
// names GCC happens to use as well. This helps simplify the implementation
@@ -31947,39 +31947,43 @@ static const char *getRetpolineSymbol(const X86Subtarget &Subtarget,
3194731947
assert(Subtarget.is64Bit() && "Should not be using a 64-bit thunk!");
3194831948
return "__x86_indirect_thunk_r11";
3194931949
}
31950-
llvm_unreachable("unexpected reg for retpoline");
31950+
llvm_unreachable("unexpected reg for external indirect thunk");
3195131951
}
3195231952

31953-
// When targeting an internal COMDAT thunk use an LLVM-specific name.
31954-
switch (Reg) {
31955-
case X86::EAX:
31956-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31957-
return "__llvm_retpoline_eax";
31958-
case X86::ECX:
31959-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31960-
return "__llvm_retpoline_ecx";
31961-
case X86::EDX:
31962-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31963-
return "__llvm_retpoline_edx";
31964-
case X86::EDI:
31965-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31966-
return "__llvm_retpoline_edi";
31967-
case X86::R11:
31968-
assert(Subtarget.is64Bit() && "Should not be using a 64-bit thunk!");
31969-
return "__llvm_retpoline_r11";
31953+
if (Subtarget.useRetpolineIndirectCalls() ||
31954+
Subtarget.useRetpolineIndirectBranches()) {
31955+
// When targeting an internal COMDAT thunk use an LLVM-specific name.
31956+
switch (Reg) {
31957+
case X86::EAX:
31958+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31959+
return "__llvm_retpoline_eax";
31960+
case X86::ECX:
31961+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31962+
return "__llvm_retpoline_ecx";
31963+
case X86::EDX:
31964+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31965+
return "__llvm_retpoline_edx";
31966+
case X86::EDI:
31967+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31968+
return "__llvm_retpoline_edi";
31969+
case X86::R11:
31970+
assert(Subtarget.is64Bit() && "Should not be using a 64-bit thunk!");
31971+
return "__llvm_retpoline_r11";
31972+
}
31973+
llvm_unreachable("unexpected reg for retpoline");
3197031974
}
31971-
llvm_unreachable("unexpected reg for retpoline");
31975+
llvm_unreachable("getIndirectThunkSymbol() invoked without thunk feature");
3197231976
}
3197331977

3197431978
MachineBasicBlock *
31975-
X86TargetLowering::EmitLoweredRetpoline(MachineInstr &MI,
31976-
MachineBasicBlock *BB) const {
31979+
X86TargetLowering::EmitLoweredIndirectThunk(MachineInstr &MI,
31980+
MachineBasicBlock *BB) const {
3197731981
// Copy the virtual register into the R11 physical register and
3197831982
// call the retpoline thunk.
3197931983
DebugLoc DL = MI.getDebugLoc();
3198031984
const X86InstrInfo *TII = Subtarget.getInstrInfo();
3198131985
Register CalleeVReg = MI.getOperand(0).getReg();
31982-
unsigned Opc = getOpcodeForRetpoline(MI.getOpcode());
31986+
unsigned Opc = getOpcodeForIndirectThunk(MI.getOpcode());
3198331987

3198431988
// Find an available scratch register to hold the callee. On 64-bit, we can
3198531989
// just use R11, but we scan for uses anyway to ensure we don't generate
@@ -32013,7 +32017,7 @@ X86TargetLowering::EmitLoweredRetpoline(MachineInstr &MI,
3201332017
report_fatal_error("calling convention incompatible with retpoline, no "
3201432018
"available registers");
3201532019

32016-
const char *Symbol = getRetpolineSymbol(Subtarget, AvailableReg);
32020+
const char *Symbol = getIndirectThunkSymbol(Subtarget, AvailableReg);
3201732021

3201832022
BuildMI(*BB, MI, DL, TII->get(TargetOpcode::COPY), AvailableReg)
3201932023
.addReg(CalleeVReg);
@@ -32789,11 +32793,11 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
3278932793
case X86::TLS_base_addr32:
3279032794
case X86::TLS_base_addr64:
3279132795
return EmitLoweredTLSAddr(MI, BB);
32792-
case X86::RETPOLINE_CALL32:
32793-
case X86::RETPOLINE_CALL64:
32794-
case X86::RETPOLINE_TCRETURN32:
32795-
case X86::RETPOLINE_TCRETURN64:
32796-
return EmitLoweredRetpoline(MI, BB);
32796+
case X86::INDIRECT_THUNK_CALL32:
32797+
case X86::INDIRECT_THUNK_CALL64:
32798+
case X86::INDIRECT_THUNK_TCRETURN32:
32799+
case X86::INDIRECT_THUNK_TCRETURN64:
32800+
return EmitLoweredIndirectThunk(MI, BB);
3279732801
case X86::CATCHRET:
3279832802
return EmitLoweredCatchRet(MI, BB);
3279932803
case X86::SEG_ALLOCA_32:

llvm/lib/Target/X86/X86ISelLowering.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,8 +1474,8 @@ namespace llvm {
14741474
MachineBasicBlock *EmitLoweredTLSCall(MachineInstr &MI,
14751475
MachineBasicBlock *BB) const;
14761476

1477-
MachineBasicBlock *EmitLoweredRetpoline(MachineInstr &MI,
1478-
MachineBasicBlock *BB) const;
1477+
MachineBasicBlock *EmitLoweredIndirectThunk(MachineInstr &MI,
1478+
MachineBasicBlock *BB) const;
14791479

14801480
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
14811481
MachineBasicBlock *MBB) const;

llvm/lib/Target/X86/X86RetpolineThunks.cpp renamed to llvm/lib/Target/X86/X86IndirectThunks.cpp

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//======- X86RetpolineThunks.cpp - Construct retpoline thunks for x86 --=====//
1+
//==- X86IndirectThunks.cpp - Construct indirect call/jump thunks for x86 --=//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,12 +7,18 @@
77
//===----------------------------------------------------------------------===//
88
/// \file
99
///
10-
/// Pass that injects an MI thunk implementing a "retpoline". This is
11-
/// a RET-implemented trampoline that is used to lower indirect calls in a way
10+
/// Pass that injects an MI thunk that is used to lower indirect calls in a way
1211
/// that prevents speculation on some x86 processors and can be used to mitigate
1312
/// security vulnerabilities due to targeted speculative execution and side
1413
/// channels such as CVE-2017-5715.
1514
///
15+
/// Currently supported thunks include:
16+
/// - Retpoline -- A RET-implemented trampoline that lowers indirect calls
17+
///
18+
/// Note that the reason that this is implemented as a MachineFunctionPass and
19+
/// not a ModulePass is that ModulePasses at this point in the LLVM X86 pipeline
20+
/// serialize all transformations, which can consume lots of memory.
21+
///
1622
/// TODO(chandlerc): All of this code could use better comments and
1723
/// documentation.
1824
///
@@ -37,21 +43,21 @@ using namespace llvm;
3743

3844
#define DEBUG_TYPE "x86-retpoline-thunks"
3945

40-
static const char ThunkNamePrefix[] = "__llvm_retpoline_";
41-
static const char R11ThunkName[] = "__llvm_retpoline_r11";
42-
static const char EAXThunkName[] = "__llvm_retpoline_eax";
43-
static const char ECXThunkName[] = "__llvm_retpoline_ecx";
44-
static const char EDXThunkName[] = "__llvm_retpoline_edx";
45-
static const char EDIThunkName[] = "__llvm_retpoline_edi";
46+
static const char RetpolineNamePrefix[] = "__llvm_retpoline_";
47+
static const char R11RetpolineName[] = "__llvm_retpoline_r11";
48+
static const char EAXRetpolineName[] = "__llvm_retpoline_eax";
49+
static const char ECXRetpolineName[] = "__llvm_retpoline_ecx";
50+
static const char EDXRetpolineName[] = "__llvm_retpoline_edx";
51+
static const char EDIRetpolineName[] = "__llvm_retpoline_edi";
4652

4753
namespace {
48-
class X86RetpolineThunks : public MachineFunctionPass {
54+
class X86IndirectThunks : public MachineFunctionPass {
4955
public:
5056
static char ID;
5157

52-
X86RetpolineThunks() : MachineFunctionPass(ID) {}
58+
X86IndirectThunks() : MachineFunctionPass(ID) {}
5359

54-
StringRef getPassName() const override { return "X86 Retpoline Thunks"; }
60+
StringRef getPassName() const override { return "X86 Indirect Thunks"; }
5561

5662
bool doInitialization(Module &M) override;
5763
bool runOnMachineFunction(MachineFunction &F) override;
@@ -72,24 +78,24 @@ class X86RetpolineThunks : public MachineFunctionPass {
7278
bool InsertedThunks = false;
7379

7480
void createThunkFunction(Module &M, StringRef Name);
75-
void insertRegReturnAddrClobber(MachineBasicBlock &MBB, unsigned Reg);
76-
void populateThunk(MachineFunction &MF, unsigned Reg);
81+
void insertRegReturnAddrClobber(MachineBasicBlock &MBB, Register Reg);
82+
void populateThunk(MachineFunction &MF, Register Reg);
7783
};
7884

7985
} // end anonymous namespace
8086

81-
FunctionPass *llvm::createX86RetpolineThunksPass() {
82-
return new X86RetpolineThunks();
87+
FunctionPass *llvm::createX86IndirectThunksPass() {
88+
return new X86IndirectThunks();
8389
}
8490

85-
char X86RetpolineThunks::ID = 0;
91+
char X86IndirectThunks::ID = 0;
8692

87-
bool X86RetpolineThunks::doInitialization(Module &M) {
93+
bool X86IndirectThunks::doInitialization(Module &M) {
8894
InsertedThunks = false;
8995
return false;
9096
}
9197

92-
bool X86RetpolineThunks::runOnMachineFunction(MachineFunction &MF) {
98+
bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
9399
LLVM_DEBUG(dbgs() << getPassName() << '\n');
94100

95101
TM = &MF.getTarget();;
@@ -102,7 +108,7 @@ bool X86RetpolineThunks::runOnMachineFunction(MachineFunction &MF) {
102108

103109
// If this function is not a thunk, check to see if we need to insert
104110
// a thunk.
105-
if (!MF.getName().startswith(ThunkNamePrefix)) {
111+
if (!MF.getName().startswith(RetpolineNamePrefix)) {
106112
// If we've already inserted a thunk, nothing else to do.
107113
if (InsertedThunks)
108114
return false;
@@ -124,10 +130,11 @@ bool X86RetpolineThunks::runOnMachineFunction(MachineFunction &MF) {
124130
// pass. We extract the module and insert a new function (and machine
125131
// function) directly into the module.
126132
if (Is64Bit)
127-
createThunkFunction(M, R11ThunkName);
133+
createThunkFunction(M, R11RetpolineName);
128134
else
129135
for (StringRef Name :
130-
{EAXThunkName, ECXThunkName, EDXThunkName, EDIThunkName})
136+
{EAXRetpolineName, ECXRetpolineName, EDXRetpolineName,
137+
EDIRetpolineName})
131138
createThunkFunction(M, Name);
132139
InsertedThunks = true;
133140
return true;
@@ -177,13 +184,13 @@ bool X86RetpolineThunks::runOnMachineFunction(MachineFunction &MF) {
177184
// ... # Same setup
178185
// movl %edi, (%esp)
179186
// retl
180-
if (MF.getName() == EAXThunkName)
187+
if (MF.getName() == EAXRetpolineName)
181188
populateThunk(MF, X86::EAX);
182-
else if (MF.getName() == ECXThunkName)
189+
else if (MF.getName() == ECXRetpolineName)
183190
populateThunk(MF, X86::ECX);
184-
else if (MF.getName() == EDXThunkName)
191+
else if (MF.getName() == EDXRetpolineName)
185192
populateThunk(MF, X86::EDX);
186-
else if (MF.getName() == EDIThunkName)
193+
else if (MF.getName() == EDIRetpolineName)
187194
populateThunk(MF, X86::EDI);
188195
else
189196
llvm_unreachable("Invalid thunk name on x86-32!");
@@ -192,8 +199,8 @@ bool X86RetpolineThunks::runOnMachineFunction(MachineFunction &MF) {
192199
return true;
193200
}
194201

195-
void X86RetpolineThunks::createThunkFunction(Module &M, StringRef Name) {
196-
assert(Name.startswith(ThunkNamePrefix) &&
202+
void X86IndirectThunks::createThunkFunction(Module &M, StringRef Name) {
203+
assert(Name.startswith(RetpolineNamePrefix) &&
197204
"Created a thunk with an unexpected prefix!");
198205

199206
LLVMContext &Ctx = M.getContext();
@@ -226,16 +233,16 @@ void X86RetpolineThunks::createThunkFunction(Module &M, StringRef Name) {
226233
MF.insert(MF.end(), EntryMBB);
227234
}
228235

229-
void X86RetpolineThunks::insertRegReturnAddrClobber(MachineBasicBlock &MBB,
230-
unsigned Reg) {
236+
void X86IndirectThunks::insertRegReturnAddrClobber(MachineBasicBlock &MBB,
237+
Register Reg) {
231238
const unsigned MovOpc = Is64Bit ? X86::MOV64mr : X86::MOV32mr;
232-
const unsigned SPReg = Is64Bit ? X86::RSP : X86::ESP;
239+
const Register SPReg = Is64Bit ? X86::RSP : X86::ESP;
233240
addRegOffset(BuildMI(&MBB, DebugLoc(), TII->get(MovOpc)), SPReg, false, 0)
234241
.addReg(Reg);
235242
}
236243

237-
void X86RetpolineThunks::populateThunk(MachineFunction &MF,
238-
unsigned Reg) {
244+
void X86IndirectThunks::populateThunk(MachineFunction &MF,
245+
Register Reg) {
239246
// Set MF properties. We never use vregs...
240247
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
241248

@@ -246,8 +253,10 @@ void X86RetpolineThunks::populateThunk(MachineFunction &MF,
246253
while (MF.size() > 1)
247254
MF.erase(std::next(MF.begin()));
248255

249-
MachineBasicBlock *CaptureSpec = MF.CreateMachineBasicBlock(Entry->getBasicBlock());
250-
MachineBasicBlock *CallTarget = MF.CreateMachineBasicBlock(Entry->getBasicBlock());
256+
MachineBasicBlock *CaptureSpec =
257+
MF.CreateMachineBasicBlock(Entry->getBasicBlock());
258+
MachineBasicBlock *CallTarget =
259+
MF.CreateMachineBasicBlock(Entry->getBasicBlock());
251260
MCSymbol *TargetSym = MF.getContext().createTempSymbol();
252261
MF.push_back(CaptureSpec);
253262
MF.push_back(CallTarget);

0 commit comments

Comments
 (0)