llvm.org GIT mirror llvm / 63dea2c
Add Forward Control-Flow Integrity. This commit adds a new pass that can inject checks before indirect calls to make sure that these calls target known locations. It supports three types of checks and, at compile time, it can take the name of a custom function to call when an indirect call check fails. The default failure function ignores the error and continues. This pass incidentally moves the function JumpInstrTables::transformType from private to public and makes it static (with a new argument that specifies the table type to use); this is so that the CFI code can transform function types at call sites to determine which jump-instruction table to use for the check at that site. Also, this removes support for jumptables in ARM, pending further performance analysis and discussion. Review: http://reviews.llvm.org/D4167 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221708 91177308-0d34-0410-b5e6-96231b3b80d8 Tom Roeder 5 years ago
29 changed file(s) with 873 addition(s) and 133 deletion(s). Raw diff Collapse all Expand all
3636 public:
3737 static char ID;
3838
39 JumpInstrTableInfo();
39 /// The default byte alignment for jump tables is 16, which is large but
40 /// usually safe.
41 JumpInstrTableInfo(uint64_t ByteAlign = 16);
4042 virtual ~JumpInstrTableInfo();
4143 const char *getPassName() const override {
4244 return "Jump-Instruction Table Info";
5153 /// Gets the tables.
5254 const JumpTables &getTables() const { return Tables; }
5355
56 /// Gets the alignment in bytes of a jumptable entry.
57 uint64_t entryByteAlignment() const { return ByteAlignment; }
5458 private:
5559 JumpTables Tables;
60
61 /// A power-of-two alignment of a jumptable entry.
62 uint64_t ByteAlignment;
5663 };
64
65 /// Creates a JumpInstrTableInfo pass with the given bound on entry size. This
66 /// bound specifies the maximum number of bytes needed to represent an
67 /// unconditional jump or a trap instruction in the back end currently in use.
68 ModulePass *createJumpInstrTableInfoPass(unsigned Bound);
5769 }
5870
5971 #endif /* LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H */
220220 clEnumValN(JumpTable::Full, "full",
221221 "Create one table per unique function type."),
222222 clEnumValEnd));
223
224 cl::opt
225 FCFI("fcfi",
226 cl::desc("Apply forward-edge control-flow integrity"),
227 cl::init(false));
228
229 cl::opt
230 CFIType("cfi-type",
231 cl::desc("Choose the type of Control-Flow Integrity check to add"),
232 cl::init(CFIntegrity::Sub),
233 cl::values(
234 clEnumValN(CFIntegrity::Sub, "sub",
235 "Subtract the pointer from the table base, then mask."),
236 clEnumValN(CFIntegrity::Ror, "ror",
237 "Use rotate to check the offset from a table base."),
238 clEnumValN(CFIntegrity::Add, "add",
239 "Mask out the high bits and add to an aligned base."),
240 clEnumValEnd));
241
242 cl::opt
243 CFIEnforcing("cfi-enforcing",
244 cl::desc("Enforce CFI or pass the violation to a function."),
245 cl::init(false));
246
247 // Note that this option is linked to the cfi-enforcing option above: if
248 // cfi-enforcing is set, then the cfi-func-name option is entirely ignored. If
249 // cfi-enforcing is false and no cfi-func-name is set, then a default function
250 // will be generated that ignores all CFI violations. The expected signature for
251 // functions called with CFI violations is
252 //
253 // void (i8*, i8*)
254 //
255 // The first pointer is a C string containing the name of the function in which
256 // the violation occurs, and the second pointer is the pointer that violated
257 // CFI.
258 cl::opt
259 CFIFuncName("cfi-func-name", cl::desc("The name of the CFI function to call"),
260 cl::init(""));
223261
224262 // Common utility function tightly tied to the options listed here. Initializes
225263 // a TargetOptions object with CodeGen flags and returns it.
248286
249287 Options.MCOptions = InitMCTargetOptionsFromFlags();
250288 Options.JTType = JTableType;
289 Options.FCFI = FCFI;
290 Options.CFIType = CFIType;
291 Options.CFIEnforcing = CFIEnforcing;
292 Options.CFIFuncName = CFIFuncName;
251293
252294 Options.ThreadModel = TMModel;
253295
0 //===-- ForwardControlFlowIntegrity.h: Forward-Edge CFI ---------*- C++ -*-===//
1 //
2 // This file is distributed under the University of Illinois Open Source
3 // License. See LICENSE.TXT for details.
4 //
5 //===----------------------------------------------------------------------===//
6 //
7 // This pass instruments indirect calls with checks to ensure that these calls
8 // pass through the appropriate jump-instruction table generated by
9 // JumpInstrTables.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
14 #define LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
15
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/Pass.h"
19 #include "llvm/Target/TargetOptions.h"
20
21 #include
22
23 namespace llvm {
24
25 class AnalysisUsage;
26 class BasicBlock;
27 class Constant;
28 class Function;
29 class Instruction;
30 class Module;
31 class Value;
32
33 /// ForwardControlFlowIntegrity uses the information from JumpInstrTableInfo to
34 /// prepend checks to indirect calls to make sure that these calls target valid
35 /// locations.
36 class ForwardControlFlowIntegrity : public ModulePass {
37 public:
38 static char ID;
39
40 ForwardControlFlowIntegrity();
41 ForwardControlFlowIntegrity(JumpTable::JumpTableType JTT,
42 CFIntegrity CFIType,
43 bool CFIEnforcing, std::string CFIFuncName);
44 virtual ~ForwardControlFlowIntegrity() override;
45
46 /// Runs the CFI pass on a given module. This works best if the module in
47 /// question is the result of link-time optimization (see lib/LTO).
48 bool runOnModule(Module &M) override;
49 const char *getPassName() const override {
50 return "Forward Control-Flow Integrity";
51 }
52 void getAnalysisUsage(AnalysisUsage &AU) const override;
53
54 private:
55 typedef SmallVector CallSet;
56
57 /// A structure that is used to keep track of constant table information.
58 struct CFIConstants {
59 Constant *StartValue;
60 Constant *MaskValue;
61 Constant *Size;
62 };
63
64 /// A map from function type to the base of the table for this type and a mask
65 /// for the table
66 typedef DenseMap CFITables;
67
68 CallSet IndirectCalls;
69
70 /// The type of jumptable implementation.
71 JumpTable::JumpTableType JTType;
72
73 /// The type of CFI check to add before each indirect call.
74 CFIntegrity CFIType;
75
76 /// A value that controls whether or not CFI violations cause a halt.
77 bool CFIEnforcing;
78
79 /// The name of the function to call in case of a CFI violation when
80 /// CFIEnforcing is false. There is a default function that ignores
81 /// violations.
82 std::string CFIFuncName;
83
84 /// The alignment of each entry in the table, from JumpInstrTableInfo. The
85 /// JumpInstrTableInfo class always makes this a power of two.
86 uint64_t ByteAlignment;
87
88 /// The base-2 logarithm of ByteAlignment, needed for some of the transforms
89 /// (like CFIntegrity::Ror)
90 unsigned LogByteAlignment;
91
92 /// Adds checks to each indirect call site to make sure that it is calling a
93 /// function in our jump table.
94 void updateIndirectCalls(Module &M, CFITables &CFIT);
95
96 /// Walks the instructions to find all the indirect calls.
97 void getIndirectCalls(Module &M);
98
99 /// Adds a function that handles violations in non-enforcing mode
100 /// (!CFIEnforcing). The default warning function simply returns, since the
101 /// exact details of how to handle CFI violations depend on the application.
102 void addWarningFunction(Module &M);
103
104 /// Rewrites a function pointer in a call/invoke instruction to force it into
105 /// a table.
106 void rewriteFunctionPointer(Module &M, Instruction *I, Value *FunPtr,
107 Constant *JumpTableStart, Constant *JumpTableMask,
108 Constant *JumpTableSize);
109
110 /// Inserts a check and a call to a warning function at a given instruction
111 /// that must be an indirect call.
112 void insertWarning(Module &M, BasicBlock *Block, Instruction *I,
113 Value *FunPtr);
114 };
115
116 ModulePass *
117 createForwardControlFlowIntegrityPass(JumpTable::JumpTableType JTT,
118 CFIntegrity CFIType,
119 bool CFIEnforcing, StringRef CFIFuncName);
120 }
121
122 #endif // LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
3838 /// jmp f_orig@PLT
3939 /// \endverbatim
4040 ///
41 /// Support for an architecture depends on two functions in TargetInstrInfo:
42 /// getUnconditionalBranch, and getTrap. AsmPrinter uses these to generate the
43 /// appropriate instructions for the jump statement (an unconditional branch)
44 /// and for padding to make the table have a size that is a power of two. This
45 /// padding uses a trap instruction to ensure that calls to this area halt the
46 /// program. The default implementations of these functions call
47 /// llvm_unreachable.
41 /// Support for an architecture depends on three functions in TargetInstrInfo:
42 /// getUnconditionalBranch, getTrap, and getJumpInstrTableEntryBound. AsmPrinter
43 /// uses these to generate the appropriate instructions for the jump statement
44 /// (an unconditional branch) and for padding to make the table have a size that
45 /// is a power of two. This padding uses a trap instruction to ensure that calls
46 /// to this area halt the program. The default implementations of these
47 /// functions call llvm_unreachable, except for getJumpInstrTableEntryBound,
48 /// which returns 0 by default.
4849 class JumpInstrTables : public ModulePass {
4950 public:
5051 static char ID;
6364 /// Checks to see if there is already a table for the given FunctionType.
6465 bool hasTable(FunctionType *FunTy);
6566
67 /// Maps the function into a subset of function types, depending on the
68 /// jump-instruction table style selected from JumpTableTypes in
69 /// JumpInstrTables.cpp. The choice of mapping determines the number of
70 /// jump-instruction tables generated by this pass. E.g., the simplest mapping
71 /// converts every function type into void f(); so, all functions end up in a
72 /// single table.
73 static FunctionType *transformType(JumpTable::JumpTableType JTT,
74 FunctionType *FunTy);
6675 private:
6776 /// The metadata used while a jump table is being built
6877 struct TableMeta {
7483 };
7584
7685 typedef DenseMap JumpMap;
77
78 /// Maps the function into a subset of function types, depending on the
79 /// jump-instruction table style selected from JumpTableTypes in
80 /// JumpInstrTables.cpp. The choice of mapping determines the number of
81 /// jump-instruction tables generated by this pass. E.g., the simplest mapping
82 /// converts every function type into void f(); so, all functions end up in a
83 /// single table.
84 FunctionType *transformType(FunctionType *FunTy);
8586
8687 /// The current state of functions and jump entries in the table(s).
8788 JumpMap Metadata;
601601
602602 /// createJumpInstrTables - This pass creates jump-instruction tables.
603603 ModulePass *createJumpInstrTablesPass();
604
605 /// createForwardControlFlowIntegrityPass - This pass adds control-flow
606 /// integrity.
607 ModulePass *createForwardControlFlowIntegrityPass();
604608 } // End llvm namespace
605609
606610 /// This initializer registers TargetMachine constructor, so the pass being
9090 void initializeCFGPrinterPass(PassRegistry&);
9191 void initializeCFGSimplifyPassPass(PassRegistry&);
9292 void initializeCFLAliasAnalysisPass(PassRegistry&);
93 void initializeForwardControlFlowIntegrityPass(PassRegistry&);
9394 void initializeFlattenCFGPassPass(PassRegistry&);
9495 void initializeStructurizeCFGPass(PassRegistry&);
9596 void initializeCFGViewerPass(PassRegistry&);
427427 llvm_unreachable("Target didn't implement TargetInstrInfo::getTrap!");
428428 }
429429
430 /// getJumpInstrTableEntryBound - Get a number of bytes that suffices to hold
431 /// either the instruction returned by getUnconditionalBranch or the
432 /// instruction returned by getTrap. This only makes sense because
433 /// getUnconditionalBranch returns a single, specific instruction. This
434 /// information is needed by the jumptable construction code, since it must
435 /// decide how many bytes to use for a jumptable entry so it can generate the
436 /// right mask.
437 ///
438 /// Note that if the jumptable instruction requires alignment, then that
439 /// alignment should be factored into this required bound so that the
440 /// resulting bound gives the right alignment for the instruction.
441 virtual unsigned getJumpInstrTableEntryBound() const {
442 // This method gets called by LLVMTargetMachine always, so it can't fail
443 // just because there happens to be no implementation for this target.
444 // Any code that tries to use a jumptable annotation without defining
445 // getUnconditionalBranch on the appropriate Target will fail anyway, and
446 // the value returned here won't matter in that case.
447 return 0;
448 }
449
430450 /// isLegalToSplitMBBAt - Return true if it's legal to split the given basic
431451 /// block at the specified instruction (i.e. instruction would be the start
432452 /// of a new basic block).
5555 Single // Single Threaded Environment
5656 };
5757 }
58
59 enum class CFIntegrity {
60 Sub, // Use subtraction-based checks.
61 Ror, // Use rotation-based checks.
62 Add // Use addition-based checks. This depends on having
63 // sufficient alignment in the code and is usually not
64 // feasible.
65 };
5866
5967 class TargetOptions {
6068 public:
6977 EnableFastISel(false), PositionIndependentExecutable(false),
7078 UseInitArray(false), DisableIntegratedAS(false),
7179 CompressDebugSections(false), FunctionSections(false),
72 DataSections(false), TrapUnreachable(false), TrapFuncName(""),
80 DataSections(false), TrapUnreachable(false), TrapFuncName(),
7381 FloatABIType(FloatABI::Default),
7482 AllowFPOpFusion(FPOpFusion::Standard), JTType(JumpTable::Single),
75 ThreadModel(ThreadModel::POSIX) {}
83 FCFI(false), ThreadModel(ThreadModel::POSIX),
84 CFIType(CFIntegrity::Sub), CFIEnforcing(false), CFIFuncName() {}
7685
7786 /// PrintMachineCode - This flag is enabled when the -print-machineinstrs
7887 /// option is specified on the command line, and should enable debugging
227236 /// create for functions that have the jumptable attribute.
228237 JumpTable::JumpTableType JTType;
229238
239 /// FCFI - This flags controls whether or not forward-edge control-flow
240 /// integrity is applied.
241 bool FCFI;
242
230243 /// ThreadModel - This flag specifies the type of threading model to assume
231244 /// for things like atomics
232245 ThreadModel::Model ThreadModel;
246
247 /// CFIType - This flag specifies the type of control-flow integrity check
248 /// to add as a preamble to indirect calls.
249 CFIntegrity CFIType;
250
251 /// CFIEnforcing - This flags controls whether or not CFI violations cause
252 /// the program to halt.
253 bool CFIEnforcing;
254
255 /// getCFIFuncName - If this returns a non-empty string, then this is the
256 /// name of the function that will be called for each CFI violation in
257 /// non-enforcing mode.
258 std::string CFIFuncName;
259 StringRef getCFIFuncName() const;
233260
234261 /// Machine level options.
235262 MCTargetOptions MCOptions;
1616 #include "llvm/Analysis/Passes.h"
1717 #include "llvm/IR/Function.h"
1818 #include "llvm/IR/Type.h"
19 #include "llvm/Support/MathExtras.h"
1920
2021 using namespace llvm;
2122
2728 return new JumpInstrTableInfo();
2829 }
2930
30 JumpInstrTableInfo::JumpInstrTableInfo() : ImmutablePass(ID), Tables() {
31 ModulePass *llvm::createJumpInstrTableInfoPass(unsigned Bound) {
32 // This cast is always safe, since Bound is always in a subset of uint64_t.
33 uint64_t B = static_cast(Bound);
34 return new JumpInstrTableInfo(B);
35 }
36
37 JumpInstrTableInfo::JumpInstrTableInfo(uint64_t ByteAlign)
38 : ImmutablePass(ID), Tables(), ByteAlignment(ByteAlign) {
39 if (!llvm::isPowerOf2_64(ByteAlign)) {
40 // Note that we don't explicitly handle overflow here, since we handle the 0
41 // case explicitly when a caller actually tries to create jumptable entries,
42 // and this is the return value on overflow.
43 ByteAlignment = llvm::NextPowerOf2(ByteAlign);
44 }
45
3146 initializeJumpInstrTableInfoPass(*PassRegistry::getPassRegistry());
3247 }
3348
878878 bool IsThumb = (Arch == Triple::thumb || Arch == Triple::thumbeb);
879879 MCInst TrapInst;
880880 TM.getSubtargetImpl()->getInstrInfo()->getTrap(TrapInst);
881 unsigned LogAlignment = llvm::Log2_64(JITI->entryByteAlignment());
882
883 // Emit the right section for these functions.
884 OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection());
881885 for (const auto &KV : JITI->getTables()) {
882886 uint64_t Count = 0;
883887 for (const auto &FunPair : KV.second) {
884888 // Emit the function labels to make this be a function entry point.
885889 MCSymbol *FunSym =
886890 OutContext.GetOrCreateSymbol(FunPair.second->getName());
887 OutStreamer.EmitSymbolAttribute(FunSym, MCSA_Global);
888 // FIXME: JumpTableInstrInfo should store information about the required
889 // alignment of table entries and the size of the padding instruction.
890 EmitAlignment(3);
891 EmitAlignment(LogAlignment);
891892 if (IsThumb)
892893 OutStreamer.EmitThumbFunc(FunSym);
893894 if (MAI->hasDotTypeDotSizeDirective())
909910 }
910911
911912 // Emit enough padding instructions to fill up to the next power of two.
912 // This assumes that the trap instruction takes 8 bytes or fewer.
913913 uint64_t Remaining = NextPowerOf2(Count) - Count;
914914 for (uint64_t C = 0; C < Remaining; ++C) {
915 EmitAlignment(3);
915 EmitAlignment(LogAlignment);
916916 OutStreamer.EmitInstruction(TrapInst, getSubtargetInfo());
917917 }
918918
1818 ExecutionDepsFix.cpp
1919 ExpandISelPseudos.cpp
2020 ExpandPostRAPseudos.cpp
21 ForwardControlFlowIntegrity.cpp
2122 GCMetadata.cpp
2223 GCMetadataPrinter.cpp
2324 GCStrategy.cpp
0 //===-- ForwardControlFlowIntegrity.cpp: Forward-Edge CFI -----------------===//
1 //
2 // This file is distributed under the University of Illinois Open Source
3 // License. See LICENSE.TXT for details.
4 //
5 //===----------------------------------------------------------------------===//
6 ///
7 /// \file
8 /// \brief A pass that instruments code with fast checks for indirect calls and
9 /// hooks for a function to check violations.
10 ///
11 //===----------------------------------------------------------------------===//
12
13 #define DEBUG_TYPE "cfi"
14
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/Analysis/JumpInstrTableInfo.h"
18 #include "llvm/CodeGen/ForwardControlFlowIntegrity.h"
19 #include "llvm/CodeGen/JumpInstrTables.h"
20 #include "llvm/CodeGen/Passes.h"
21 #include "llvm/IR/Attributes.h"
22 #include "llvm/IR/CallSite.h"
23 #include "llvm/IR/Constants.h"
24 #include "llvm/IR/DerivedTypes.h"
25 #include "llvm/IR/Function.h"
26 #include "llvm/IR/GlobalValue.h"
27 #include "llvm/IR/Instructions.h"
28 #include "llvm/IR/InlineAsm.h"
29 #include "llvm/IR/IRBuilder.h"
30 #include "llvm/IR/LLVMContext.h"
31 #include "llvm/IR/Module.h"
32 #include "llvm/IR/Operator.h"
33 #include "llvm/IR/Type.h"
34 #include "llvm/IR/Verifier.h"
35 #include "llvm/Pass.h"
36 #include "llvm/Support/CommandLine.h"
37 #include "llvm/Support/Debug.h"
38 #include "llvm/Support/raw_ostream.h"
39
40 using namespace llvm;
41
42 STATISTIC(NumCFIIndirectCalls,
43 "Number of indirect call sites rewritten by the CFI pass");
44
45 char ForwardControlFlowIntegrity::ID = 0;
46 INITIALIZE_PASS_BEGIN(ForwardControlFlowIntegrity, "forward-cfi",
47 "Control-Flow Integrity", true, true)
48 INITIALIZE_PASS_DEPENDENCY(JumpInstrTableInfo);
49 INITIALIZE_PASS_DEPENDENCY(JumpInstrTables);
50 INITIALIZE_PASS_END(ForwardControlFlowIntegrity, "forward-cfi",
51 "Control-Flow Integrity", true, true)
52
53 ModulePass *llvm::createForwardControlFlowIntegrityPass() {
54 return new ForwardControlFlowIntegrity();
55 }
56
57 ModulePass *llvm::createForwardControlFlowIntegrityPass(
58 JumpTable::JumpTableType JTT, CFIntegrity CFIType, bool CFIEnforcing,
59 StringRef CFIFuncName) {
60 return new ForwardControlFlowIntegrity(JTT, CFIType, CFIEnforcing,
61 CFIFuncName);
62 }
63
64 // Checks to see if a given CallSite is making an indirect call, including
65 // cases where the indirect call is made through a bitcast.
66 static bool isIndirectCall(CallSite &CS) {
67 if (CS.getCalledFunction())
68 return false;
69
70 // Check the value to see if it is merely a bitcast of a function. In
71 // this case, it will translate to a direct function call in the resulting
72 // assembly, so we won't treat it as an indirect call here.
73 const Value *V = CS.getCalledValue();
74 if (const ConstantExpr *CE = dyn_cast(V)) {
75 return !(CE->isCast() && isa(CE->getOperand(0)));
76 }
77
78 // Otherwise, since we know it's a call, it must be an indirect call
79 return true;
80 }
81
82 static const char cfi_failure_func_name[] = "__llvm_cfi_pointer_warning";
83 static const char cfi_func_name_prefix[] = "__llvm_cfi_function_";
84
85 ForwardControlFlowIntegrity::ForwardControlFlowIntegrity()
86 : ModulePass(ID), IndirectCalls(), JTType(JumpTable::Single),
87 CFIType(CFIntegrity::Sub), CFIEnforcing(false), CFIFuncName("") {
88 initializeForwardControlFlowIntegrityPass(*PassRegistry::getPassRegistry());
89 }
90
91 ForwardControlFlowIntegrity::ForwardControlFlowIntegrity(
92 JumpTable::JumpTableType JTT, CFIntegrity CFIType, bool CFIEnforcing,
93 std::string CFIFuncName)
94 : ModulePass(ID), IndirectCalls(), JTType(JTT), CFIType(CFIType),
95 CFIEnforcing(CFIEnforcing), CFIFuncName(CFIFuncName) {
96 initializeForwardControlFlowIntegrityPass(*PassRegistry::getPassRegistry());
97 }
98
99 ForwardControlFlowIntegrity::~ForwardControlFlowIntegrity() {}
100
101 void ForwardControlFlowIntegrity::getAnalysisUsage(AnalysisUsage &AU) const {
102 AU.addRequired();
103 AU.addRequired();
104 }
105
106 void ForwardControlFlowIntegrity::getIndirectCalls(Module &M) {
107 // To get the indirect calls, we iterate over all functions and iterate over
108 // the list of basic blocks in each. We extract a total list of indirect calls
109 // before modifying any of them, since our modifications will modify the list
110 // of basic blocks.
111 for (Function &F : M) {
112 for (BasicBlock &BB : F) {
113 for (Instruction &I : BB) {
114 CallSite CS(&I);
115 if (!(CS && isIndirectCall(CS)))
116 continue;
117
118 Value *CalledValue = CS.getCalledValue();
119
120 // Don't rewrite this instruction if the indirect call is actually just
121 // inline assembly, since our transformation will generate an invalid
122 // module in that case.
123 if (isa(CalledValue))
124 continue;
125
126 IndirectCalls.push_back(&I);
127 }
128 }
129 }
130 }
131
132 void ForwardControlFlowIntegrity::updateIndirectCalls(Module &M,
133 CFITables &CFIT) {
134 Type *Int64Ty = Type::getInt64Ty(M.getContext());
135 for (Instruction *I : IndirectCalls) {
136 CallSite CS(I);
137 Value *CalledValue = CS.getCalledValue();
138
139 // Get the function type for this call and look it up in the tables.
140 Type *VTy = CalledValue->getType();
141 PointerType *PTy = dyn_cast(VTy);
142 Type *EltTy = PTy->getElementType();
143 FunctionType *FunTy = dyn_cast(EltTy);
144 FunctionType *TransformedTy = JumpInstrTables::transformType(JTType, FunTy);
145 ++NumCFIIndirectCalls;
146 Constant *JumpTableStart = nullptr;
147 Constant *JumpTableMask = nullptr;
148 Constant *JumpTableSize = nullptr;
149
150 // Some call sites have function types that don't correspond to any
151 // address-taken function in the module. This happens when function pointers
152 // are passed in from external code.
153 auto it = CFIT.find(TransformedTy);
154 if (it == CFIT.end()) {
155 // In this case, make sure that the function pointer will change by
156 // setting the mask and the start to be 0 so that the transformed
157 // function is 0.
158 JumpTableStart = ConstantInt::get(Int64Ty, 0);
159 JumpTableMask = ConstantInt::get(Int64Ty, 0);
160 JumpTableSize = ConstantInt::get(Int64Ty, 0);
161 } else {
162 JumpTableStart = it->second.StartValue;
163 JumpTableMask = it->second.MaskValue;
164 JumpTableSize = it->second.Size;
165 }
166
167 rewriteFunctionPointer(M, I, CalledValue, JumpTableStart, JumpTableMask,
168 JumpTableSize);
169 }
170
171 return;
172 }
173
174 bool ForwardControlFlowIntegrity::runOnModule(Module &M) {
175 JumpInstrTableInfo *JITI = &getAnalysis();
176 Type *Int64Ty = Type::getInt64Ty(M.getContext());
177 Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
178
179 // JumpInstrTableInfo stores information about the alignment of each entry.
180 // The alignment returned by JumpInstrTableInfo is alignment in bytes, not
181 // in the exponent.
182 ByteAlignment = JITI->entryByteAlignment();
183 LogByteAlignment = llvm::Log2_64(ByteAlignment);
184
185 // Set up tables for control-flow integrity based on information about the
186 // jump-instruction tables.
187 CFITables CFIT;
188 for (const auto &KV : JITI->getTables()) {
189 uint64_t Size = static_cast(KV.second.size());
190 uint64_t TableSize = NextPowerOf2(Size);
191
192 int64_t MaskValue = ((TableSize << LogByteAlignment) - 1) & -ByteAlignment;
193 Constant *JumpTableMaskValue = ConstantInt::get(Int64Ty, MaskValue);
194 Constant *JumpTableSize = ConstantInt::get(Int64Ty, Size);
195
196 // The base of the table is defined to be the first jumptable function in
197 // the table.
198 Function *First = KV.second.begin()->second;
199 Constant *JumpTableStartValue = ConstantExpr::getBitCast(First, VoidPtrTy);
200 CFIT[KV.first].StartValue = JumpTableStartValue;
201 CFIT[KV.first].MaskValue = JumpTableMaskValue;
202 CFIT[KV.first].Size = JumpTableSize;
203 }
204
205 if (CFIT.empty())
206 return false;
207
208 getIndirectCalls(M);
209
210 if (!CFIEnforcing) {
211 addWarningFunction(M);
212 }
213
214 // Update the instructions with the check and the indirect jump through our
215 // table.
216 updateIndirectCalls(M, CFIT);
217
218 return true;
219 }
220
221 void ForwardControlFlowIntegrity::addWarningFunction(Module &M) {
222 PointerType *CharPtrTy = Type::getInt8PtrTy(M.getContext());
223
224 // Get the type of the Warning Function: void (i8*, i8*),
225 // where the first argument is the name of the function in which the violation
226 // occurs, and the second is the function pointer that violates CFI.
227 SmallVector WarningFunArgs;
228 WarningFunArgs.push_back(CharPtrTy);
229 WarningFunArgs.push_back(CharPtrTy);
230 FunctionType *WarningFunTy =
231 FunctionType::get(Type::getVoidTy(M.getContext()), WarningFunArgs, false);
232
233 if (!CFIFuncName.empty()) {
234 Constant *FailureFun = M.getOrInsertFunction(CFIFuncName, WarningFunTy);
235 if (!FailureFun)
236 report_fatal_error("Could not get or insert the function specified by"
237 " -cfi-func-name");
238 } else {
239 // The default warning function swallows the warning and lets the call
240 // continue, since there's no generic way for it to print out this
241 // information.
242 Function *WarningFun = M.getFunction(cfi_failure_func_name);
243 if (!WarningFun) {
244 WarningFun =
245 Function::Create(WarningFunTy, GlobalValue::LinkOnceAnyLinkage,
246 cfi_failure_func_name, &M);
247 }
248
249 BasicBlock *Entry =
250 BasicBlock::Create(M.getContext(), "entry", WarningFun, 0);
251 ReturnInst::Create(M.getContext(), Entry);
252 }
253 }
254
255 void ForwardControlFlowIntegrity::rewriteFunctionPointer(
256 Module &M, Instruction *I, Value *FunPtr, Constant *JumpTableStart,
257 Constant *JumpTableMask, Constant *JumpTableSize) {
258 IRBuilder<> TempBuilder(I);
259
260 Type *OrigFunType = FunPtr->getType();
261
262 BasicBlock *CurBB = cast(I->getParent());
263 Function *CurF = cast(CurBB->getParent());
264 Type *Int64Ty = Type::getInt64Ty(M.getContext());
265
266 Value *TI = TempBuilder.CreatePtrToInt(FunPtr, Int64Ty);
267 Value *TStartInt = TempBuilder.CreatePtrToInt(JumpTableStart, Int64Ty);
268
269 Value *NewFunPtr = nullptr;
270 Value *Check = nullptr;
271 switch (CFIType) {
272 case CFIntegrity::Sub: {
273 // This is the subtract, mask, and add version.
274 // Subtract from the base.
275 Value *Sub = TempBuilder.CreateSub(TI, TStartInt);
276
277 // Mask the difference to force this to be a table offset.
278 Value *And = TempBuilder.CreateAnd(Sub, JumpTableMask);
279
280 // Add it back to the base.
281 Value *Result = TempBuilder.CreateAdd(And, TStartInt);
282
283 // Convert it back into a function pointer that we can call.
284 NewFunPtr = TempBuilder.CreateIntToPtr(Result, OrigFunType);
285 break;
286 }
287 case CFIntegrity::Ror: {
288 // This is the subtract and rotate version.
289 // Rotate right by the alignment value. The optimizer should recognize
290 // this sequence as a rotation.
291
292 // This cast is safe, since unsigned is always a subset of uint64_t.
293 uint64_t LogByteAlignment64 = static_cast(LogByteAlignment);
294 Constant *RightShift = ConstantInt::get(Int64Ty, LogByteAlignment64);
295 Constant *LeftShift = ConstantInt::get(Int64Ty, 64 - LogByteAlignment64);
296
297 // Subtract from the base.
298 Value *Sub = TempBuilder.CreateSub(TI, TStartInt);
299
300 // Create the equivalent of a rotate-right instruction.
301 Value *Shr = TempBuilder.CreateLShr(Sub, RightShift);
302 Value *Shl = TempBuilder.CreateShl(Sub, LeftShift);
303 Value *Or = TempBuilder.CreateOr(Shr, Shl);
304
305 // Perform unsigned comparison to check for inclusion in the table.
306 Check = TempBuilder.CreateICmpULT(Or, JumpTableSize);
307 NewFunPtr = FunPtr;
308 break;
309 }
310 case CFIntegrity::Add: {
311 // This is the mask and add version.
312 // Mask the function pointer to turn it into an offset into the table.
313 Value *And = TempBuilder.CreateAnd(TI, JumpTableMask);
314
315 // Then or this offset to the base and get the pointer value.
316 Value *Result = TempBuilder.CreateAdd(And, TStartInt);
317
318 // Convert it back into a function pointer that we can call.
319 NewFunPtr = TempBuilder.CreateIntToPtr(Result, OrigFunType);
320 break;
321 }
322 }
323
324 if (!CFIEnforcing) {
325 // If a check hasn't been added (in the rotation version), then check to see
326 // if it's the same as the original function. This check determines whether
327 // or not we call the CFI failure function.
328 if (!Check)
329 Check = TempBuilder.CreateICmpEQ(NewFunPtr, FunPtr);
330 BasicBlock *InvalidPtrBlock =
331 BasicBlock::Create(M.getContext(), "invalid.ptr", CurF, 0);
332 BasicBlock *ContinuationBB = CurBB->splitBasicBlock(I);
333
334 // Remove the unconditional branch that connects the two blocks.
335 TerminatorInst *TermInst = CurBB->getTerminator();
336 TermInst->eraseFromParent();
337
338 // Add a conditional branch that depends on the Check above.
339 BranchInst::Create(ContinuationBB, InvalidPtrBlock, Check, CurBB);
340
341 // Call the warning function for this pointer, then continue.
342 Instruction *BI = BranchInst::Create(ContinuationBB, InvalidPtrBlock);
343 insertWarning(M, InvalidPtrBlock, BI, FunPtr);
344 } else {
345 // Modify the instruction to call this value.
346 CallSite CS(I);
347 CS.setCalledFunction(NewFunPtr);
348 }
349 }
350
351 void ForwardControlFlowIntegrity::insertWarning(Module &M, BasicBlock *Block,
352 Instruction *I, Value *FunPtr) {
353 Function *ParentFun = cast(Block->getParent());
354
355 // Get the function to call right before the instruction.
356 Function *WarningFun = nullptr;
357 if (CFIFuncName.empty()) {
358 WarningFun = M.getFunction(cfi_failure_func_name);
359 } else {
360 WarningFun = M.getFunction(CFIFuncName);
361 }
362
363 assert(WarningFun && "Could not find the CFI failure function");
364
365 Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
366
367 IRBuilder<> WarningInserter(I);
368 // Create a mergeable GlobalVariable containing the name of the function.
369 Value *ParentNameGV =
370 WarningInserter.CreateGlobalString(ParentFun->getName());
371 Value *ParentNamePtr = WarningInserter.CreateBitCast(ParentNameGV, VoidPtrTy);
372 Value *FunVoidPtr = WarningInserter.CreateBitCast(FunPtr, VoidPtrTy);
373 WarningInserter.CreateCall2(WarningFun, ParentNamePtr, FunVoidPtr);
374 }
162162
163163 Function *JumpInstrTables::insertEntry(Module &M, Function *Target) {
164164 FunctionType *OrigFunTy = Target->getFunctionType();
165 FunctionType *FunTy = transformType(OrigFunTy);
165 FunctionType *FunTy = transformType(JTType, OrigFunTy);
166166
167167 JumpMap::iterator it = Metadata.find(FunTy);
168168 if (Metadata.end() == it) {
190190 }
191191
192192 bool JumpInstrTables::hasTable(FunctionType *FunTy) {
193 FunctionType *TransTy = transformType(FunTy);
193 FunctionType *TransTy = transformType(JTType, FunTy);
194194 return Metadata.end() != Metadata.find(TransTy);
195195 }
196196
197 FunctionType *JumpInstrTables::transformType(FunctionType *FunTy) {
197 FunctionType *JumpInstrTables::transformType(JumpTable::JumpTableType JTT,
198 FunctionType *FunTy) {
198199 // Returning nullptr forces all types into the same table, since all types map
199200 // to the same type
200201 Type *VoidPtrTy = Type::getInt8PtrTy(FunTy->getContext());
210211 Type *Int32Ty = Type::getInt32Ty(FunTy->getContext());
211212 FunctionType *VoidFnTy = FunctionType::get(
212213 Type::getVoidTy(FunTy->getContext()), EmptyParams, false);
213 switch (JTType) {
214 switch (JTT) {
214215 case JumpTable::Single:
215216
216217 return FunctionType::get(RetTy, EmptyParams, false);
252253 bool JumpInstrTables::runOnModule(Module &M) {
253254 JITI = &getAnalysis();
254255
255 // Get the set of jumptable-annotated functions.
256 // Get the set of jumptable-annotated functions that have their address taken.
256257 DenseMap Functions;
257258 for (Function &F : M) {
258 if (F.hasFnAttribute(Attribute::JumpTable)) {
259 if (F.hasFnAttribute(Attribute::JumpTable) && F.hasAddressTaken()) {
259260 assert(F.hasUnnamedAddr() &&
260261 "Attribute 'jumptable' requires 'unnamed_addr'");
261262 Functions[&F] = nullptr;
1212
1313 #include "llvm/Target/TargetMachine.h"
1414
15 #include "llvm/Analysis/JumpInstrTableInfo.h"
1516 #include "llvm/Analysis/Passes.h"
1617 #include "llvm/CodeGen/AsmPrinter.h"
18 #include "llvm/CodeGen/ForwardControlFlowIntegrity.h"
1719 #include "llvm/CodeGen/JumpInstrTables.h"
1820 #include "llvm/CodeGen/MachineFunctionAnalysis.h"
1921 #include "llvm/CodeGen/MachineModuleInfo.h"
142144 AnalysisID StopAfter) {
143145 // Passes to handle jumptable function annotations. These can't be handled at
144146 // JIT time, so we don't add them directly to addPassesToGenerateCode.
145 PM.add(createJumpInstrTableInfoPass());
147 PM.add(createJumpInstrTableInfoPass(
148 getSubtargetImpl()->getInstrInfo()->getJumpInstrTableEntryBound()));
146149 PM.add(createJumpInstrTablesPass(Options.JTType));
150 if (Options.FCFI)
151 PM.add(createForwardControlFlowIntegrityPass(
152 Options.JTType, Options.CFIType, Options.CFIEnforcing,
153 Options.getCFIFuncName()));
147154
148155 // Add common CodeGen passes.
149156 MCContext *Context = addPassesToGenerateCode(this, PM, DisableVerify,
5050 StringRef TargetOptions::getTrapFunctionName() const {
5151 return TrapFuncName;
5252 }
53
54 /// getCFIFuncName - If this returns a non-empty string, then it is the name of
55 /// the function that gets called on CFI violations in CFI non-enforcing mode
56 /// (!TargetOptions::CFIEnforcing).
57 StringRef TargetOptions::getCFIFuncName() const {
58 return CFIFuncName;
59 }
44884488 MI->addRegisterKilled(DReg, TRI, true);
44894489 }
44904490
4491 void ARMBaseInstrInfo::getUnconditionalBranch(
4492 MCInst &Branch, const MCSymbolRefExpr *BranchTarget) const {
4493 if (Subtarget.isThumb())
4494 Branch.setOpcode(ARM::tB);
4495 else if (Subtarget.isThumb2())
4496 Branch.setOpcode(ARM::t2B);
4497 else
4498 Branch.setOpcode(ARM::Bcc);
4499
4500 Branch.addOperand(MCOperand::CreateExpr(BranchTarget));
4501 Branch.addOperand(MCOperand::CreateImm(ARMCC::AL));
4502 Branch.addOperand(MCOperand::CreateReg(0));
4503 }
4504
4505 void ARMBaseInstrInfo::getTrap(MCInst &MI) const {
4506 if (Subtarget.isThumb())
4507 MI.setOpcode(ARM::tTRAP);
4508 else if (Subtarget.useNaClTrap())
4509 MI.setOpcode(ARM::TRAPNaCl);
4510 else
4511 MI.setOpcode(ARM::TRAP);
4512 }
4513
45144491 bool ARMBaseInstrInfo::hasNOP() const {
45154492 return (Subtarget.getFeatureBits() & ARM::HasV6T2Ops) != 0;
45164493 }
287287 const TargetRegisterInfo*) const override;
288288 void breakPartialRegDependency(MachineBasicBlock::iterator, unsigned,
289289 const TargetRegisterInfo *TRI) const override;
290
291 void
292 getUnconditionalBranch(MCInst &Branch,
293 const MCSymbolRefExpr *BranchTarget) const override;
294
295 void getTrap(MCInst &MI) const override;
296290
297291 /// Get the number of addresses by LDM or VLDM or zero for unknown.
298292 unsigned getNumLDMAddresses(const MachineInstr *MI) const;
54765476 NopInst.setOpcode(X86::NOOP);
54775477 }
54785478
5479 // This code must remain in sync with getJumpInstrTableEntryBound in this class!
5480 // In particular, getJumpInstrTableEntryBound must always return an upper bound
5481 // on the encoding lengths of the instructions generated by
5482 // getUnconditionalBranch and getTrap.
54795483 void X86InstrInfo::getUnconditionalBranch(
54805484 MCInst &Branch, const MCSymbolRefExpr *BranchTarget) const {
54815485 Branch.setOpcode(X86::JMP_4);
54825486 Branch.addOperand(MCOperand::CreateExpr(BranchTarget));
54835487 }
54845488
5489 // This code must remain in sync with getJumpInstrTableEntryBound in this class!
5490 // In particular, getJumpInstrTableEntryBound must always return an upper bound
5491 // on the encoding lengths of the instructions generated by
5492 // getUnconditionalBranch and getTrap.
54855493 void X86InstrInfo::getTrap(MCInst &MI) const {
54865494 MI.setOpcode(X86::TRAP);
5495 }
5496
5497 // See getTrap and getUnconditionalBranch for conditions on the value returned
5498 // by this function.
5499 unsigned X86InstrInfo::getJumpInstrTableEntryBound() const {
5500 // 5 bytes suffice: JMP_4 Symbol@PLT is uses 1 byte (E9) for the JMP_4 and 4
5501 // bytes for the symbol offset. And TRAP is ud2, which is two bytes (0F 0B).
5502 return 5;
54875503 }
54885504
54895505 bool X86InstrInfo::isHighLatencyDef(int opc) const {
412412
413413 void getTrap(MCInst &MI) const override;
414414
415 unsigned getJumpInstrTableEntryBound() const override;
416
415417 bool isHighLatencyDef(int opc) const override;
416418
417419 bool hasHighOperandLatency(const InstrItineraryData *ItinData,
+0
-32
test/CodeGen/ARM/jump_tables.ll less more
None ; RUN: llc <%s -mtriple=arm-unknown-linux-gnueabi -jump-table-type=single | FileCheck --check-prefix=ARM %s
1 ; RUN: llc <%s -mtriple=thumb-unknown-linux-gnueabi -jump-table-type=single | FileCheck --check-prefix=THUMB %s
2
3 define void @indirect_fun() unnamed_addr jumptable {
4 ret void
5 }
6 define void ()* @get_fun() {
7 ret void ()* @indirect_fun
8
9 ; ARM: ldr r0, [[LABEL:.*]]
10 ; ARM: mov pc, lr
11 ; ARM: [[LABEL]]:
12 ; ARM: .long __llvm_jump_instr_table_0_1
13
14 ; THUMB: ldr r0, [[LABEL:.*]]
15 ; THUMB: bx lr
16 ; THUMB: [[LABEL]]:
17 ; THUMB: .long __llvm_jump_instr_table_0_1
18 }
19
20 ; ARM: .globl __llvm_jump_instr_table_0_1
21 ; ARM: .align 3
22 ; ARM: .type __llvm_jump_instr_table_0_1,%function
23 ; ARM: __llvm_jump_instr_table_0_1:
24 ; ARM: b indirect_fun(PLT)
25
26 ; THUMB: .globl __llvm_jump_instr_table_0_1
27 ; THUMB: .align 3
28 ; THUMB: .thumb_func
29 ; THUMB: .type __llvm_jump_instr_table_0_1,%function
30 ; THUMB: __llvm_jump_instr_table_0_1:
31 ; THUMB: b indirect_fun(PLT)
0 ; RUN: llc -mtriple=i386-unknown-linux-gnu -fcfi -cfi-enforcing <%s | FileCheck --check-prefix=X86 %s
1 ; RUN: llc -mtriple=x86_64-unknown-linux-gnu -fcfi -cfi-enforcing <%s | FileCheck --check-prefix=X86-64 %s
2
3 define void @indirect_fun() unnamed_addr jumptable {
4 ret void
5 }
6
7 define i32 @m(void ()* %fun) {
8 call void ()* %fun()
9 ; CHECK: subl
10 ; X86-64: andq $8,
11 ; X86-64: leaq __llvm_jump_instr_table_0_1({{%[a-z0-9]+}}), [[REG:%[a-z0-9]+]]
12 ; X86-64-NOT: callq __llvm_cfi_pointer_warning
13 ; X86-64: callq *[[REG]]
14 ; X86: andl $8,
15 ; X86: leal __llvm_jump_instr_table_0_1({{%[a-z0-9]+}}), [[REG:%[a-z0-9]+]]
16 ; X86-NOT: calll __llvm_cfi_pointer_warning
17 ; X86: calll *[[REG]]
18 ret i32 0
19 }
20
21 define void ()* @get_fun() {
22 ret void ()* @indirect_fun
23 }
24
25 define i32 @main(i32 %argc, i8** %argv) {
26 %f = call void ()* ()* @get_fun()
27 %a = call i32 @m(void ()* %f)
28 ret i32 %a
29 }
30
31 ; CHECK: .align 8
32 ; CHECK: __llvm_jump_instr_table_0_1:
33 ; CHECK: jmp indirect_fun@PLT
0 ; RUN: llc <%s -fcfi -cfi-type=sub | FileCheck %s
1 ; ModuleID = 'test.cc'
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-unknown-linux-gnu"
4
5 declare i32 @__gxx_personality_v0(...)
6
7 @_ZTIPKc = external constant i8*
8 @_ZTIi = external constant i8*
9
10 define void @f() unnamed_addr jumptable {
11 ret void
12 }
13
14 @a = global void ()* @f
15
16 ; Make sure invoke gets targeted as well as regular calls
17 define void @_Z3foov(void ()* %f) uwtable ssp {
18 ; CHECK-LABEL: _Z3foov:
19 entry:
20 invoke void %f()
21 to label %try.cont unwind label %lpad
22 ; CHECK: callq __llvm_cfi_pointer_warning
23 ; CHECK: callq *%rbx
24
25 lpad:
26 %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
27 catch i8* bitcast (i8** @_ZTIi to i8*)
28 filter [1 x i8*] [i8* bitcast (i8** @_ZTIPKc to i8*)]
29 ret void
30
31 try.cont:
32 ret void
33 }
34
0 ; RUN: llc -fcfi -cfi-func-name=cfi_new_failure <%s | FileCheck %s
1
2 target triple = "x86_64-unknown-linux-gnu"
3 define void @indirect_fun() unnamed_addr jumptable {
4 ret void
5 }
6
7 define i32 @m(void ()* %fun) {
8 ; CHECK-LABEL: @m
9 call void ()* %fun()
10 ; CHECK: callq cfi_new_failure
11 ret i32 0
12 }
13
14 define void ()* @get_fun() {
15 ret void ()* @indirect_fun
16 }
17
18 define i32 @main(i32 %argc, i8** %argv) {
19 %f = call void ()* ()* @get_fun()
20 %a = call i32 @m(void ()* %f)
21 ret i32 %a
22 }
23
24 ; CHECK: .align 8
25 ; CHECK: __llvm_jump_instr_table_0_1:
26 ; CHECK: jmp indirect_fun@PLT
0 ; RUN: llc -fcfi -cfi-type=sub <%s | FileCheck --check-prefix=SUB %s
1 ; RUN: llc -fcfi -cfi-type=add <%s | FileCheck --check-prefix=ADD %s
2 ; RUN: llc -fcfi -cfi-type=ror <%s | FileCheck --check-prefix=ROR %s
3
4 target triple = "x86_64-unknown-linux-gnu"
5
6 define void @indirect_fun() unnamed_addr jumptable {
7 ret void
8 }
9
10 define i32 @m(void ()* %fun) {
11 call void ()* %fun()
12 ; SUB: subl
13 ; SUB: andq $8
14 ; SUB-LABEL: leaq __llvm_jump_instr_table_0_1
15 ; SUB-LABEL: callq __llvm_cfi_pointer_warning
16
17 ; ROR: subq
18 ; ROR: rolq $61
19 ; ROR: testq
20 ; ROR-LABEL: callq __llvm_cfi_pointer_warning
21
22 ; ADD: andq $8
23 ; ADD-LABEL: leaq __llvm_jump_instr_table_0_1
24 ; ADD: cmpq
25 ; ADD-LABEL: callq __llvm_cfi_pointer_warning
26 ret i32 0
27 }
28
29 define void ()* @get_fun() {
30 ret void ()* @indirect_fun
31 }
32
33 define i32 @main(i32 %argc, i8** %argv) {
34 %f = call void ()* ()* @get_fun()
35 %a = call i32 @m(void ()* %f)
36 ret i32 %a
37 }
38 ; SUB: .text
39 ; SUB: .align 8
40 ; SUB-LABEL: .type __llvm_jump_instr_table_0_1,@function
41 ; SUB-LABEL:__llvm_jump_instr_table_0_1:
42 ; SUB-LABEL: jmp indirect_fun@PLT
2424 ; There should only be one table, even though there are two GlobalAliases,
2525 ; because they both alias the same value.
2626
27 ; CHECK: .globl __llvm_jump_instr_table_0_1
2827 ; CHECK: .align 8, 0x90
2928 ; CHECK: .type __llvm_jump_instr_table_0_1,@function
3029 ; CHECK: __llvm_jump_instr_table_0_1:
0 ; RUN: llc -filetype=obj <%s -jump-table-type=single -o %t1
1 ; RUN: llvm-objdump -triple=x86_64-unknown-linux-gnu -d %t1 | FileCheck %s
2 target triple = "x86_64-unknown-linux-gnu"
3 define i32 @f() unnamed_addr jumptable {
4 ret i32 0
5 }
6
7 define i32 @g(i8* %a) unnamed_addr jumptable {
8 ret i32 0
9 }
10
11 define void @h(void ()* %func) unnamed_addr jumptable {
12 ret void
13 }
14
15 define i32 @main() {
16 %g = alloca i32 (...)*, align 8
17 store i32 (...)* bitcast (i32 ()* @f to i32 (...)*), i32 (...)** %g, align 8
18 %1 = load i32 (...)** %g, align 8
19 %call = call i32 (...)* %1()
20 call void (void ()*)* @h(void ()* bitcast (void (void ()*)* @h to void ()*))
21 %a = call i32 (i32*)* bitcast (i32 (i8*)* @g to i32(i32*)*)(i32* null)
22 ret i32 %a
23 }
24
25 ; Make sure that the padding from getJumpInstrTableEntryBound is right.
26 ; CHECK: __llvm_jump_instr_table_0_1:
27 ; CHECK-NEXT: e9 00 00 00 00 jmp 0
28 ; CHECK-NEXT: 0f 1f 00 nopl (%rax)
1414 define i32 @main() {
1515 %g = alloca i32 (...)*, align 8
1616 store i32 (...)* bitcast (i32 ()* @f to i32 (...)*), i32 (...)** %g, align 8
17 ; CHECK: movq $__llvm_jump_instr_table_0_[[ENTRY:1|2|3]], (%rsp)
18 ; CHECK: movl $__llvm_jump_instr_table_0_[[ENTRY]], %ecx
17 ; CHECK: movq $__llvm_jump_instr_table_0_[[ENTRY:1|2|3]],
18 ; CHECK: movl $__llvm_jump_instr_table_0_[[ENTRY]],
1919 %1 = load i32 (...)** %g, align 8
2020 %call = call i32 (...)* %1()
2121 call void (void ()*)* @h(void ()* bitcast (void (void ()*)* @h to void ()*))
22 ; CHECK: movl $__llvm_jump_instr_table_0_{{1|2|3}}, %edi
22 ; CHECK: movl $__llvm_jump_instr_table_0_{{1|2|3}},
2323 ; CHECK: callq h
2424
2525 %a = call i32 (i32*)* bitcast (i32 (i8*)* @g to i32(i32*)*)(i32* null)
2727 ret i32 %a
2828 }
2929
30 ; CHECK: .globl __llvm_jump_instr_table_0_1
3130 ; CHECK: .align 8, 0x90
3231 ; CHECK: .type __llvm_jump_instr_table_0_1,@function
3332 ; CHECK: __llvm_jump_instr_table_0_1:
3433 ; CHECK: jmp {{f|g|h}}@PLT
35 ; CHECK: .globl __llvm_jump_instr_table_0_2
3634 ; CHECK: .align 8, 0x90
3735 ; CHECK: .type __llvm_jump_instr_table_0_2,@function
3836 ; CHECK: __llvm_jump_instr_table_0_2:
3937 ; CHECK: jmp {{f|g|h}}@PLT
40 ; CHECK: .globl __llvm_jump_instr_table_0_3
4138 ; CHECK: .align 8, 0x90
4239 ; CHECK: .type __llvm_jump_instr_table_0_3,@function
4340 ; CHECK: __llvm_jump_instr_table_0_3:
55 target triple = "x86_64-unknown-linux-gnu"
66
77 %struct.fun_struct = type { i32 (...)* }
8
9 @a = global [12 x i32 () *] [ i32 ()* bitcast (void ()* @indirect_fun to i32 ()*),
10 i32 ()* bitcast (void ()* @indirect_fun_match to i32 ()*),
11 i32 ()* bitcast (i32 ()* @indirect_fun_i32 to i32 ()*),
12 i32 ()* bitcast (i32 (i32)* @indirect_fun_i32_1 to i32 ()*),
13 i32 ()* bitcast (i32 (i32, i32)* @indirect_fun_i32_2 to i32 ()*),
14 i32 ()* bitcast (i32* (i32*, i32)* @indirect_fun_i32S_2 to i32 ()*),
15 i32 ()* bitcast (void (%struct.fun_struct)* @indirect_fun_struct to i32 ()*),
16 i32 ()* bitcast (void (i32 (...)*, i32)* @indirect_fun_fun to i32 ()*),
17 i32 ()* bitcast (i32 (i32 (...)*, i32)* @indirect_fun_fun_ret to i32 ()*),
18 i32 ()* bitcast (void ([19 x i8])* @indirect_fun_array to i32 ()*),
19 i32 ()* bitcast (void (<3 x i32>)* @indirect_fun_vec to i32 ()*),
20 i32 ()* bitcast (void (<4 x float>)* @indirect_fun_vec_2 to i32 ()*)
21 ]
822
923 define void @indirect_fun() unnamed_addr jumptable {
1024 ret void
7387 ret i32 %a
7488 }
7589
76 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_1
7790 ; SINGLE-DAG: .align 8, 0x90
7891 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_1,@function
7992 ; SINGLE-DAG: __llvm_jump_instr_table_0_1:
8093 ; SINGLE-DAG: jmp indirect_fun_array@PLT
81 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_2
8294 ; SINGLE-DAG: .align 8, 0x90
8395 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_2,@function
8496 ; SINGLE-DAG: __llvm_jump_instr_table_0_2:
8597 ; SINGLE-DAG: jmp indirect_fun_i32_2@PLT
86 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_3
8798 ; SINGLE-DAG: .align 8, 0x90
8899 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_3,@function
89100 ; SINGLE-DAG: __llvm_jump_instr_table_0_3:
90101 ; SINGLE-DAG: jmp indirect_fun_vec_2@PLT
91 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_4
92102 ; SINGLE-DAG: .align 8, 0x90
93103 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_4,@function
94104 ; SINGLE-DAG: __llvm_jump_instr_table_0_4:
95105 ; SINGLE-DAG: jmp indirect_fun_i32S_2@PLT
96 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_5
97106 ; SINGLE-DAG: .align 8, 0x90
98107 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_5,@function
99108 ; SINGLE-DAG: __llvm_jump_instr_table_0_5:
100109 ; SINGLE-DAG: jmp indirect_fun_struct@PLT
101 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_6
102110 ; SINGLE-DAG: .align 8, 0x90
103111 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_6,@function
104112 ; SINGLE-DAG: __llvm_jump_instr_table_0_6:
105113 ; SINGLE-DAG: jmp indirect_fun_i32_1@PLT
106 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_7
107114 ; SINGLE-DAG: .align 8, 0x90
108115 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_7,@function
109116 ; SINGLE-DAG: __llvm_jump_instr_table_0_7:
110117 ; SINGLE-DAG: jmp indirect_fun_i32@PLT
111 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_8
112118 ; SINGLE-DAG: .align 8, 0x90
113119 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_8,@function
114120 ; SINGLE-DAG: __llvm_jump_instr_table_0_8:
115121 ; SINGLE-DAG: jmp indirect_fun_fun@PLT
116 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_9
117122 ; SINGLE-DAG: .align 8, 0x90
118123 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_9,@function
119124 ; SINGLE-DAG: __llvm_jump_instr_table_0_9:
120125 ; SINGLE-DAG: jmp indirect_fun_fun_ret@PLT
121 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_10
122126 ; SINGLE-DAG: .align 8, 0x90
123127 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_10,@function
124128 ; SINGLE-DAG: __llvm_jump_instr_table_0_10:
125129 ; SINGLE-DAG: jmp indirect_fun@PLT
126 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_11
127130 ; SINGLE-DAG: .align 8, 0x90
128131 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_11,@function
129132 ; SINGLE-DAG: __llvm_jump_instr_table_0_11:
130133 ; SINGLE-DAG: jmp indirect_fun_match@PLT
131 ; SINGLE-DAG: .globl __llvm_jump_instr_table_0_12
132134 ; SINGLE-DAG: .align 8, 0x90
133135 ; SINGLE-DAG: .type __llvm_jump_instr_table_0_12,@function
134136 ; SINGLE-DAG: __llvm_jump_instr_table_0_12:
143145 ; SINGLE-DAG: ud2
144146
145147
146 ; ARITY-DAG: .globl __llvm_jump_instr_table_2_1
147148 ; ARITY-DAG: .align 8, 0x90
148149 ; ARITY-DAG: .type __llvm_jump_instr_table_2_1,@function
149150 ; ARITY-DAG: __llvm_jump_instr_table_2_1:
150151 ; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
151152 ; ARITY-DAG: .align 8, 0x90
152153 ; ARITY-DAG: ud2
153 ; ARITY-DAG: .globl __llvm_jump_instr_table_0_1
154154 ; ARITY-DAG: .align 8, 0x90
155155 ; ARITY-DAG: .type __llvm_jump_instr_table_0_1,@function
156156 ; ARITY-DAG: __llvm_jump_instr_table_0_1:
157157 ; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
158 ; ARITY-DAG: .globl __llvm_jump_instr_table_1_1
159158 ; ARITY-DAG: .align 8, 0x90
160159 ; ARITY-DAG: .type __llvm_jump_instr_table_1_1,@function
161160 ; ARITY-DAG: __llvm_jump_instr_table_1_1:
162161 ; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
163162
164 ; SIMPL-DAG: .globl __llvm_jump_instr_table_2_1
165163 ; SIMPL-DAG: .align 8, 0x90
166164 ; SIMPL-DAG: .type __llvm_jump_instr_table_2_1,@function
167165 ; SIMPL-DAG: __llvm_jump_instr_table_2_1:
168166 ; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
169167 ; SIMPL-DAG: .align 8, 0x90
170168 ; SIMPL-DAG: ud2
171 ; SIMPL-DAG: .globl __llvm_jump_instr_table_0_1
172169 ; SIMPL-DAG: .align 8, 0x90
173170 ; SIMPL-DAG: .type __llvm_jump_instr_table_0_1,@function
174171 ; SIMPL-DAG: __llvm_jump_instr_table_0_1:
175172 ; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
176 ; SIMPL-DAG: .globl __llvm_jump_instr_table_1_1
177173 ; SIMPL-DAG: .align 8, 0x90
178174 ; SIMPL-DAG: .type __llvm_jump_instr_table_1_1,@function
179175 ; SIMPL-DAG: __llvm_jump_instr_table_1_1:
180176 ; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
181 ; SIMPL-DAG: .globl __llvm_jump_instr_table_3_1
182177 ; SIMPL-DAG: .align 8, 0x90
183178 ; SIMPL-DAG: .type __llvm_jump_instr_table_3_1,@function
184179 ; SIMPL-DAG: __llvm_jump_instr_table_3_1:
185180 ; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
186 ; SIMPL-DAG: .globl __llvm_jump_instr_table_4_1
187181 ; SIMPL-DAG: .align 8, 0x90
188182 ; SIMPL-DAG: .type __llvm_jump_instr_table_4_1,@function
189183 ; SIMPL-DAG: __llvm_jump_instr_table_4_1:
190184 ; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
191185
192186
193 ; FULL-DAG: .globl __llvm_jump_instr_table_10_1
194187 ; FULL-DAG: .align 8, 0x90
195188 ; FULL-DAG: .type __llvm_jump_instr_table_10_1,@function
196189 ; FULL-DAG:__llvm_jump_instr_table_10_1:
197190 ; FULL-DAG: jmp indirect_fun_i32_1@PLT
198191 ; FULL-DAG: .align 8, 0x90
199192 ; FULL-DAG: ud2
200 ; FULL-DAG: .globl __llvm_jump_instr_table_9_1
201193 ; FULL-DAG: .align 8, 0x90
202194 ; FULL-DAG: .type __llvm_jump_instr_table_9_1,@function
203195 ; FULL-DAG:__llvm_jump_instr_table_9_1:
204196 ; FULL-DAG: jmp indirect_fun_i32_2@PLT
205197 ; FULL-DAG: .align 8, 0x90
206198 ; FULL-DAG: ud2
207 ; FULL-DAG: .globl __llvm_jump_instr_table_7_1
208199 ; FULL-DAG: .align 8, 0x90
209200 ; FULL-DAG: .type __llvm_jump_instr_table_7_1,@function
210201 ; FULL-DAG:__llvm_jump_instr_table_7_1:
211202 ; FULL-DAG: jmp indirect_fun_i32S_2@PLT
212203 ; FULL-DAG: .align 8, 0x90
213204 ; FULL-DAG: ud2
214 ; FULL-DAG: .globl __llvm_jump_instr_table_3_1
215205 ; FULL-DAG: .align 8, 0x90
216206 ; FULL-DAG: .type __llvm_jump_instr_table_3_1,@function
217207 ; FULL-DAG:__llvm_jump_instr_table_3_1:
218208 ; FULL-DAG: jmp indirect_fun_vec_2@PLT
219209 ; FULL-DAG: .align 8, 0x90
220210 ; FULL-DAG: ud2
221 ; FULL-DAG: .globl __llvm_jump_instr_table_2_1
222211 ; FULL-DAG: .align 8, 0x90
223212 ; FULL-DAG: .type __llvm_jump_instr_table_2_1,@function
224213 ; FULL-DAG:__llvm_jump_instr_table_2_1:
227216 ; FULL-DAG: ud2
228217 ; FULL-DAG: .align 8, 0x90
229218 ; FULL-DAG: ud2
230 ; FULL-DAG: .globl __llvm_jump_instr_table_8_1
231219 ; FULL-DAG: .align 8, 0x90
232220 ; FULL-DAG: .type __llvm_jump_instr_table_8_1,@function
233221 ; FULL-DAG:__llvm_jump_instr_table_8_1:
234222 ; FULL-DAG: jmp indirect_fun_i32@PLT
235223 ; FULL-DAG: .align 8, 0x90
236224 ; FULL-DAG: ud2
237 ; FULL-DAG: .globl __llvm_jump_instr_table_1_1
238225 ; FULL-DAG: .align 8, 0x90
239226 ; FULL-DAG: .type __llvm_jump_instr_table_1_1,@function
240227 ; FULL-DAG:__llvm_jump_instr_table_1_1:
241228 ; FULL-DAG: jmp indirect_fun_array@PLT
242229 ; FULL-DAG: .align 8, 0x90
243230 ; FULL-DAG: ud2
244 ; FULL-DAG: .globl __llvm_jump_instr_table_0_1
245231 ; FULL-DAG: .align 8, 0x90
246232 ; FULL-DAG: .type __llvm_jump_instr_table_0_1,@function
247233 ; FULL-DAG:__llvm_jump_instr_table_0_1:
248234 ; FULL-DAG: jmp indirect_fun_vec@PLT
249235 ; FULL-DAG: .align 8, 0x90
250236 ; FULL-DAG: ud2
251 ; FULL-DAG: .globl __llvm_jump_instr_table_6_1
252237 ; FULL-DAG: .align 8, 0x90
253238 ; FULL-DAG: .type __llvm_jump_instr_table_6_1,@function
254239 ; FULL-DAG:__llvm_jump_instr_table_6_1:
255240 ; FULL-DAG: jmp indirect_fun_struct@PLT
256241 ; FULL-DAG: .align 8, 0x90
257242 ; FULL-DAG: ud2
258 ; FULL-DAG: .globl __llvm_jump_instr_table_5_1
259243 ; FULL-DAG: .align 8, 0x90
260244 ; FULL-DAG: .type __llvm_jump_instr_table_5_1,@function
261245 ; FULL-DAG:__llvm_jump_instr_table_5_1:
262246 ; FULL-DAG: jmp indirect_fun_fun@PLT
263247 ; FULL-DAG: .align 8, 0x90
264248 ; FULL-DAG: ud2
265 ; FULL-DAG: .globl __llvm_jump_instr_table_4_1
266249 ; FULL-DAG: .align 8, 0x90
267250 ; FULL-DAG: .type __llvm_jump_instr_table_4_1,@function
268251 ; FULL-DAG:__llvm_jump_instr_table_4_1:
11 ; RUN: llvm-lto -o %t2 %t1 -jump-table-type=arity
22 ; RUN: llvm-nm %t2 | FileCheck %s
33
4 ; CHECK: T __llvm_jump_instr_table_0_1
5 ; CHECK: T __llvm_jump_instr_table_1_1
4 ; CHECK: t __llvm_jump_instr_table_0_1
5 ; CHECK: t __llvm_jump_instr_table_1_1
66
77 target triple = "x86_64-unknown-linux-gnu"
88