Skip to content

Commit a59d807

Browse files
scottconstableJethro Beekman
authored and
Jethro Beekman
committed
[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 31537e6 commit a59d807

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
@@ -58,7 +59,6 @@ set(sources
5859
X86PadShortFunction.cpp
5960
X86RegisterBankInfo.cpp
6061
X86RegisterInfo.cpp
61-
X86RetpolineThunks.cpp
6262
X86SelectionDAGInfo.cpp
6363
X86ShuffleDecodeConstantPool.cpp
6464
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
@@ -3202,8 +3202,8 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
32023202
(CalledFn && CalledFn->hasFnAttribute("no_caller_saved_registers")))
32033203
return false;
32043204

3205-
// Functions using retpoline for indirect calls need to use SDISel.
3206-
if (Subtarget->useRetpolineIndirectCalls())
3205+
// Functions using thunks for indirect calls need to use SDISel.
3206+
if (Subtarget->useIndirectThunkCalls())
32073207
return false;
32083208

32093209
// 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
@@ -765,10 +765,10 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
765765
bool InProlog) const {
766766
bool IsLargeCodeModel = MF.getTarget().getCodeModel() == CodeModel::Large;
767767

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

773773
unsigned CallOp;
774774
if (Is64Bit)
@@ -2493,9 +2493,9 @@ void X86FrameLowering::adjustForSegmentedStacks(
24932493
// is laid out within 2^31 bytes of each function body, but this seems
24942494
// to be sufficient for JIT.
24952495
// FIXME: Add retpoline support and remove the error here..
2496-
if (STI.useRetpolineIndirectCalls())
2496+
if (STI.useIndirectThunkCalls())
24972497
report_fatal_error("Emitting morestack calls on 64-bit with the large "
2498-
"code model and retpoline not yet implemented.");
2498+
"code model and thunks not yet implemented.");
24992499
BuildMI(allocMBB, DL, TII.get(X86::CALL64m))
25002500
.addReg(X86::RIP)
25012501
.addImm(0)

llvm/lib/Target/X86/X86ISelDAGToDAG.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ void X86DAGToDAGISel::PreprocessISelDAG() {
987987
if (OptLevel != CodeGenOpt::None &&
988988
// Only do this when the target can fold the load into the call or
989989
// jmp.
990-
!Subtarget->useRetpolineIndirectCalls() &&
990+
!Subtarget->useIndirectThunkCalls() &&
991991
((N->getOpcode() == X86ISD::CALL && !Subtarget->slowTwoMemOps()) ||
992992
(N->getOpcode() == X86ISD::TC_RETURN &&
993993
(Subtarget->is64Bit() ||

llvm/lib/Target/X86/X86ISelLowering.cpp

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

3022030220
bool X86TargetLowering::areJTsAllowed(const Function *Fn) const {
30221-
// If the subtarget is using retpolines, we need to not generate jump tables.
30222-
if (Subtarget.useRetpolineIndirectBranches())
30221+
// If the subtarget is using thunks, we need to not generate jump tables.
30222+
if (Subtarget.useIndirectThunkBranches())
3022330223
return false;
3022430224

3022530225
// Otherwise, fallback on the generic logic.
@@ -31342,22 +31342,22 @@ X86TargetLowering::EmitLoweredTLSCall(MachineInstr &MI,
3134231342
return BB;
3134331343
}
3134431344

31345-
static unsigned getOpcodeForRetpoline(unsigned RPOpc) {
31345+
static unsigned getOpcodeForIndirectThunk(unsigned RPOpc) {
3134631346
switch (RPOpc) {
31347-
case X86::RETPOLINE_CALL32:
31347+
case X86::INDIRECT_THUNK_CALL32:
3134831348
return X86::CALLpcrel32;
31349-
case X86::RETPOLINE_CALL64:
31349+
case X86::INDIRECT_THUNK_CALL64:
3135031350
return X86::CALL64pcrel32;
31351-
case X86::RETPOLINE_TCRETURN32:
31351+
case X86::INDIRECT_THUNK_TCRETURN32:
3135231352
return X86::TCRETURNdi;
31353-
case X86::RETPOLINE_TCRETURN64:
31353+
case X86::INDIRECT_THUNK_TCRETURN64:
3135431354
return X86::TCRETURNdi64;
3135531355
}
31356-
llvm_unreachable("not retpoline opcode");
31356+
llvm_unreachable("not indirect thunk opcode");
3135731357
}
3135831358

31359-
static const char *getRetpolineSymbol(const X86Subtarget &Subtarget,
31360-
unsigned Reg) {
31359+
static const char *getIndirectThunkSymbol(const X86Subtarget &Subtarget,
31360+
unsigned Reg) {
3136131361
if (Subtarget.useRetpolineExternalThunk()) {
3136231362
// When using an external thunk for retpolines, we pick names that match the
3136331363
// names GCC happens to use as well. This helps simplify the implementation
@@ -31389,39 +31389,43 @@ static const char *getRetpolineSymbol(const X86Subtarget &Subtarget,
3138931389
assert(Subtarget.is64Bit() && "Should not be using a 64-bit thunk!");
3139031390
return "__x86_indirect_thunk_r11";
3139131391
}
31392-
llvm_unreachable("unexpected reg for retpoline");
31392+
llvm_unreachable("unexpected reg for external indirect thunk");
3139331393
}
3139431394

31395-
// When targeting an internal COMDAT thunk use an LLVM-specific name.
31396-
switch (Reg) {
31397-
case X86::EAX:
31398-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31399-
return "__llvm_retpoline_eax";
31400-
case X86::ECX:
31401-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31402-
return "__llvm_retpoline_ecx";
31403-
case X86::EDX:
31404-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31405-
return "__llvm_retpoline_edx";
31406-
case X86::EDI:
31407-
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31408-
return "__llvm_retpoline_edi";
31409-
case X86::R11:
31410-
assert(Subtarget.is64Bit() && "Should not be using a 64-bit thunk!");
31411-
return "__llvm_retpoline_r11";
31395+
if (Subtarget.useRetpolineIndirectCalls() ||
31396+
Subtarget.useRetpolineIndirectBranches()) {
31397+
// When targeting an internal COMDAT thunk use an LLVM-specific name.
31398+
switch (Reg) {
31399+
case X86::EAX:
31400+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31401+
return "__llvm_retpoline_eax";
31402+
case X86::ECX:
31403+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31404+
return "__llvm_retpoline_ecx";
31405+
case X86::EDX:
31406+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31407+
return "__llvm_retpoline_edx";
31408+
case X86::EDI:
31409+
assert(!Subtarget.is64Bit() && "Should not be using a 32-bit thunk!");
31410+
return "__llvm_retpoline_edi";
31411+
case X86::R11:
31412+
assert(Subtarget.is64Bit() && "Should not be using a 64-bit thunk!");
31413+
return "__llvm_retpoline_r11";
31414+
}
31415+
llvm_unreachable("unexpected reg for retpoline");
3141231416
}
31413-
llvm_unreachable("unexpected reg for retpoline");
31417+
llvm_unreachable("getIndirectThunkSymbol() invoked without thunk feature");
3141431418
}
3141531419

3141631420
MachineBasicBlock *
31417-
X86TargetLowering::EmitLoweredRetpoline(MachineInstr &MI,
31418-
MachineBasicBlock *BB) const {
31421+
X86TargetLowering::EmitLoweredIndirectThunk(MachineInstr &MI,
31422+
MachineBasicBlock *BB) const {
3141931423
// Copy the virtual register into the R11 physical register and
3142031424
// call the retpoline thunk.
3142131425
DebugLoc DL = MI.getDebugLoc();
3142231426
const X86InstrInfo *TII = Subtarget.getInstrInfo();
3142331427
Register CalleeVReg = MI.getOperand(0).getReg();
31424-
unsigned Opc = getOpcodeForRetpoline(MI.getOpcode());
31428+
unsigned Opc = getOpcodeForIndirectThunk(MI.getOpcode());
3142531429

3142631430
// Find an available scratch register to hold the callee. On 64-bit, we can
3142731431
// just use R11, but we scan for uses anyway to ensure we don't generate
@@ -31455,7 +31459,7 @@ X86TargetLowering::EmitLoweredRetpoline(MachineInstr &MI,
3145531459
report_fatal_error("calling convention incompatible with retpoline, no "
3145631460
"available registers");
3145731461

31458-
const char *Symbol = getRetpolineSymbol(Subtarget, AvailableReg);
31462+
const char *Symbol = getIndirectThunkSymbol(Subtarget, AvailableReg);
3145931463

3146031464
BuildMI(*BB, MI, DL, TII->get(TargetOpcode::COPY), AvailableReg)
3146131465
.addReg(CalleeVReg);
@@ -32231,11 +32235,11 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
3223132235
case X86::TLS_base_addr32:
3223232236
case X86::TLS_base_addr64:
3223332237
return EmitLoweredTLSAddr(MI, BB);
32234-
case X86::RETPOLINE_CALL32:
32235-
case X86::RETPOLINE_CALL64:
32236-
case X86::RETPOLINE_TCRETURN32:
32237-
case X86::RETPOLINE_TCRETURN64:
32238-
return EmitLoweredRetpoline(MI, BB);
32238+
case X86::INDIRECT_THUNK_CALL32:
32239+
case X86::INDIRECT_THUNK_CALL64:
32240+
case X86::INDIRECT_THUNK_TCRETURN32:
32241+
case X86::INDIRECT_THUNK_TCRETURN64:
32242+
return EmitLoweredIndirectThunk(MI, BB);
3223932243
case X86::CATCHRET:
3224032244
return EmitLoweredCatchRet(MI, BB);
3224132245
case X86::CATCHPAD:

llvm/lib/Target/X86/X86ISelLowering.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,8 +1482,8 @@ namespace llvm {
14821482
MachineBasicBlock *EmitLoweredTLSCall(MachineInstr &MI,
14831483
MachineBasicBlock *BB) const;
14841484

1485-
MachineBasicBlock *EmitLoweredRetpoline(MachineInstr &MI,
1486-
MachineBasicBlock *BB) const;
1485+
MachineBasicBlock *EmitLoweredIndirectThunk(MachineInstr &MI,
1486+
MachineBasicBlock *BB) const;
14871487

14881488
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
14891489
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)