//
FunctionPass *createMemDepPrinter();
- // createJumpInstrTableInfoPass - This creates a pass that stores information
- // about the jump tables created by JumpInstrTables
- ImmutablePass *createJumpInstrTableInfoPass();
-
//===--------------------------------------------------------------------===//
//
// createMemDerefPrinter - This pass collects memory dereferenceability
+++ /dev/null
-//===-- ForwardControlFlowIntegrity.h: Forward-Edge CFI ---------*- C++ -*-===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This pass instruments indirect calls with checks to ensure that these calls
-// pass through the appropriate jump-instruction table generated by
-// JumpInstrTables.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
-#define LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Pass.h"
-#include "llvm/Target/TargetOptions.h"
-#include <string>
-
-namespace llvm {
-
-class AnalysisUsage;
-class BasicBlock;
-class Constant;
-class Function;
-class Instruction;
-class Module;
-class Value;
-
-/// ForwardControlFlowIntegrity uses the information from JumpInstrTableInfo to
-/// prepend checks to indirect calls to make sure that these calls target valid
-/// locations.
-class ForwardControlFlowIntegrity : public ModulePass {
-public:
- static char ID;
-
- ForwardControlFlowIntegrity();
- ForwardControlFlowIntegrity(JumpTable::JumpTableType JTT,
- CFIntegrity CFIType,
- bool CFIEnforcing, std::string CFIFuncName);
- ~ForwardControlFlowIntegrity() override;
-
- /// Runs the CFI pass on a given module. This works best if the module in
- /// question is the result of link-time optimization (see lib/LTO).
- bool runOnModule(Module &M) override;
- const char *getPassName() const override {
- return "Forward Control-Flow Integrity";
- }
- void getAnalysisUsage(AnalysisUsage &AU) const override;
-
-private:
- typedef SmallVector<Instruction *, 64> CallSet;
-
- /// A structure that is used to keep track of constant table information.
- struct CFIConstants {
- Constant *StartValue;
- Constant *MaskValue;
- Constant *Size;
- };
-
- /// A map from function type to the base of the table for this type and a mask
- /// for the table
- typedef DenseMap<FunctionType *, CFIConstants> CFITables;
-
- CallSet IndirectCalls;
-
- /// The type of jumptable implementation.
- JumpTable::JumpTableType JTType;
-
- /// The type of CFI check to add before each indirect call.
- CFIntegrity CFIType;
-
- /// A value that controls whether or not CFI violations cause a halt.
- bool CFIEnforcing;
-
- /// The name of the function to call in case of a CFI violation when
- /// CFIEnforcing is false. There is a default function that ignores
- /// violations.
- std::string CFIFuncName;
-
- /// The alignment of each entry in the table, from JumpInstrTableInfo. The
- /// JumpInstrTableInfo class always makes this a power of two.
- uint64_t ByteAlignment;
-
- /// The base-2 logarithm of ByteAlignment, needed for some of the transforms
- /// (like CFIntegrity::Ror)
- unsigned LogByteAlignment;
-
- /// Adds checks to each indirect call site to make sure that it is calling a
- /// function in our jump table.
- void updateIndirectCalls(Module &M, CFITables &CFIT);
-
- /// Walks the instructions to find all the indirect calls.
- void getIndirectCalls(Module &M);
-
- /// Adds a function that handles violations in non-enforcing mode
- /// (!CFIEnforcing). The default warning function simply returns, since the
- /// exact details of how to handle CFI violations depend on the application.
- void addWarningFunction(Module &M);
-
- /// Rewrites a function pointer in a call/invoke instruction to force it into
- /// a table.
- void rewriteFunctionPointer(Module &M, Instruction *I, Value *FunPtr,
- Constant *JumpTableStart, Constant *JumpTableMask,
- Constant *JumpTableSize);
-
- /// Inserts a check and a call to a warning function at a given instruction
- /// that must be an indirect call.
- void insertWarning(Module &M, BasicBlock *Block, Instruction *I,
- Value *FunPtr);
-};
-
-ModulePass *
-createForwardControlFlowIntegrityPass(JumpTable::JumpTableType JTT,
- CFIntegrity CFIType,
- bool CFIEnforcing, StringRef CFIFuncName);
-}
-
-#endif // LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
+++ /dev/null
-//===-- JumpInstrTables.h: Jump-Instruction Tables --------------*- C++ -*-===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief An implementation of tables consisting of jump instructions
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CODEGEN_JUMPINSTRTABLES_H
-#define LLVM_CODEGEN_JUMPINSTRTABLES_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/Pass.h"
-#include "llvm/Target/TargetOptions.h"
-
-namespace llvm {
-class Constant;
-class Function;
-class FunctionType;
-class JumpInstrTableInfo;
-class Module;
-
-/// A class to manage a set of jump tables indexed on function type. It looks at
-/// each function in the module to find all the functions that have the
-/// jumptable attribute set. For each such function, it creates a new
-/// jump-instruction-table function and stores the mapping in the ImmutablePass
-/// JumpInstrTableInfo.
-///
-/// These special functions get lowered in AsmPrinter to assembly of the form:
-/// \verbatim
-/// .globl f
-/// .type f,@function
-/// .align 8,0x90
-/// f:
-/// jmp f_orig@PLT
-/// \endverbatim
-///
-/// Support for an architecture depends on three functions in TargetInstrInfo:
-/// getUnconditionalBranch, getTrap, and getJumpInstrTableEntryBound. AsmPrinter
-/// uses these to generate the appropriate instructions for the jump statement
-/// (an unconditional branch) and for padding to make the table have a size that
-/// is a power of two. This padding uses a trap instruction to ensure that calls
-/// to this area halt the program. The default implementations of these
-/// functions call llvm_unreachable, except for getJumpInstrTableEntryBound,
-/// which returns 0 by default.
-class JumpInstrTables : public ModulePass {
-public:
- static char ID;
-
- JumpInstrTables();
- JumpInstrTables(JumpTable::JumpTableType JTT);
- virtual ~JumpInstrTables();
- bool runOnModule(Module &M) override;
- const char *getPassName() const override { return "Jump-Instruction Tables"; }
- void getAnalysisUsage(AnalysisUsage &AU) const override;
-
- /// Creates a jump-instruction table function for the Target and adds it to
- /// the tables.
- Function *insertEntry(Module &M, Function *Target);
-
- /// Checks to see if there is already a table for the given FunctionType.
- bool hasTable(FunctionType *FunTy);
-
- /// Maps the function into a subset of function types, depending on the
- /// jump-instruction table style selected from JumpTableTypes in
- /// JumpInstrTables.cpp. The choice of mapping determines the number of
- /// jump-instruction tables generated by this pass. E.g., the simplest mapping
- /// converts every function type into void f(); so, all functions end up in a
- /// single table.
- static FunctionType *transformType(JumpTable::JumpTableType JTT,
- FunctionType *FunTy);
-private:
- /// The metadata used while a jump table is being built
- struct TableMeta {
- /// The number of this table
- unsigned TableNum;
-
- /// The current number of jump entries in the table.
- unsigned Count;
- };
-
- typedef DenseMap<FunctionType *, struct TableMeta> JumpMap;
-
- /// The current state of functions and jump entries in the table(s).
- JumpMap Metadata;
-
- /// The ImmutablePass that stores information about the generated tables.
- JumpInstrTableInfo *JITI;
-
- /// The total number of tables.
- unsigned TableCount;
-
- /// The type of tables to build.
- JumpTable::JumpTableType JTType;
-};
-
-/// Creates a JumpInstrTables pass for the given type of jump table.
-ModulePass *createJumpInstrTablesPass(JumpTable::JumpTableType JTT);
-}
-
-#endif /* LLVM_CODEGEN_JUMPINSTRTABLES_H */
void initializeInstNamerPass(PassRegistry&);
void initializeInternalizePassPass(PassRegistry&);
void initializeIntervalPartitionPass(PassRegistry&);
-void initializeJumpInstrTableInfoPass(PassRegistry&);
-void initializeJumpInstrTablesPass(PassRegistry&);
void initializeJumpThreadingPass(PassRegistry&);
void initializeLCSSAPass(PassRegistry&);
void initializeLICMPass(PassRegistry&);
(void) llvm::createIndVarSimplifyPass();
(void) llvm::createInstructionCombiningPass();
(void) llvm::createInternalizePass();
- (void) llvm::createJumpInstrTableInfoPass();
- (void) llvm::createJumpInstrTablesPass();
(void) llvm::createLCSSAPass();
(void) llvm::createLICMPass();
(void) llvm::createLazyValueInfoPass();
initializeIVUsersPass(Registry);
initializeInstCountPass(Registry);
initializeIntervalPartitionPass(Registry);
- initializeJumpInstrTableInfoPass(Registry);
initializeLazyValueInfoPass(Registry);
initializeLibCallAliasAnalysisPass(Registry);
initializeLintPass(Registry);
InstructionSimplify.cpp
Interval.cpp
IntervalPartition.cpp
- JumpInstrTableInfo.cpp
LazyCallGraph.cpp
LazyValueInfo.cpp
LibCallAliasAnalysis.cpp
+++ /dev/null
-//===-- JumpInstrTableInfo.cpp: Info for Jump-Instruction Tables ----------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Information about jump-instruction tables that have been created by
-/// JumpInstrTables pass.
-///
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "jiti"
-
-#include "llvm/Analysis/JumpInstrTableInfo.h"
-#include "llvm/Analysis/Passes.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/Type.h"
-#include "llvm/Support/MathExtras.h"
-
-using namespace llvm;
-
-INITIALIZE_PASS(JumpInstrTableInfo, "jump-instr-table-info",
- "Jump-Instruction Table Info", true, true)
-char JumpInstrTableInfo::ID = 0;
-
-ImmutablePass *llvm::createJumpInstrTableInfoPass() {
- return new JumpInstrTableInfo();
-}
-
-ModulePass *llvm::createJumpInstrTableInfoPass(unsigned Bound) {
- // This cast is always safe, since Bound is always in a subset of uint64_t.
- uint64_t B = static_cast<uint64_t>(Bound);
- return new JumpInstrTableInfo(B);
-}
-
-JumpInstrTableInfo::JumpInstrTableInfo(uint64_t ByteAlign)
- : ImmutablePass(ID), Tables(), ByteAlignment(ByteAlign) {
- if (!llvm::isPowerOf2_64(ByteAlign)) {
- // Note that we don't explicitly handle overflow here, since we handle the 0
- // case explicitly when a caller actually tries to create jumptable entries,
- // and this is the return value on overflow.
- ByteAlignment = llvm::NextPowerOf2(ByteAlign);
- }
-
- initializeJumpInstrTableInfoPass(*PassRegistry::getPassRegistry());
-}
-
-JumpInstrTableInfo::~JumpInstrTableInfo() {}
-
-void JumpInstrTableInfo::insertEntry(FunctionType *TableFunTy, Function *Target,
- Function *Jump) {
- Tables[TableFunTy].push_back(JumpPair(Target, Jump));
-}
EmitVisibility(Name, V, false);
}
- // Get information about jump-instruction tables to print.
- JumpInstrTableInfo *JITI = getAnalysisIfAvailable<JumpInstrTableInfo>();
-
- if (JITI && !JITI->getTables().empty()) {
- // Since we're at the module level we can't use a function specific
- // MCSubtargetInfo - instead create one with the module defaults.
- std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo(
- TM.getTargetTriple(), TM.getTargetCPU(), TM.getTargetFeatureString()));
- unsigned Arch = Triple(getTargetTriple()).getArch();
- bool IsThumb = (Arch == Triple::thumb || Arch == Triple::thumbeb);
- const TargetInstrInfo *TII = TM.getSubtargetImpl()->getInstrInfo();
- MCInst TrapInst;
- TII->getTrap(TrapInst);
- unsigned LogAlignment = llvm::Log2_64(JITI->entryByteAlignment());
-
- // Emit the right section for these functions.
- OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection());
- for (const auto &KV : JITI->getTables()) {
- uint64_t Count = 0;
- for (const auto &FunPair : KV.second) {
- // Emit the function labels to make this be a function entry point.
- MCSymbol *FunSym =
- OutContext.GetOrCreateSymbol(FunPair.second->getName());
- EmitAlignment(LogAlignment);
- if (IsThumb)
- OutStreamer.EmitThumbFunc(FunSym);
- if (MAI->hasDotTypeDotSizeDirective())
- OutStreamer.EmitSymbolAttribute(FunSym, MCSA_ELF_TypeFunction);
- OutStreamer.EmitLabel(FunSym);
-
- // Emit the jump instruction to transfer control to the original
- // function.
- MCInst JumpToFun;
- MCSymbol *TargetSymbol =
- OutContext.GetOrCreateSymbol(FunPair.first->getName());
- const MCSymbolRefExpr *TargetSymRef =
- MCSymbolRefExpr::Create(TargetSymbol, MCSymbolRefExpr::VK_PLT,
- OutContext);
- TII->getUnconditionalBranch(JumpToFun, TargetSymRef);
- OutStreamer.EmitInstruction(JumpToFun, *STI);
- ++Count;
- }
-
- // Emit enough padding instructions to fill up to the next power of two.
- uint64_t Remaining = NextPowerOf2(Count) - Count;
- for (uint64_t C = 0; C < Remaining; ++C) {
- EmitAlignment(LogAlignment);
- OutStreamer.EmitInstruction(TrapInst, *STI);
- }
-
- }
- }
-
// Emit module flags.
SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
M.getModuleFlagsMetadata(ModuleFlags);
ExecutionDepsFix.cpp
ExpandISelPseudos.cpp
ExpandPostRAPseudos.cpp
- ForwardControlFlowIntegrity.cpp
GCMetadata.cpp
GCMetadataPrinter.cpp
GCRootLowering.cpp
InlineSpiller.cpp
InterferenceCache.cpp
IntrinsicLowering.cpp
- JumpInstrTables.cpp
LLVMTargetMachine.cpp
LatencyPriorityQueue.cpp
LexicalScopes.cpp
+++ /dev/null
-//===-- ForwardControlFlowIntegrity.cpp: Forward-Edge CFI -----------------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief A pass that instruments code with fast checks for indirect calls and
-/// hooks for a function to check violations.
-///
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "cfi"
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/JumpInstrTableInfo.h"
-#include "llvm/CodeGen/ForwardControlFlowIntegrity.h"
-#include "llvm/CodeGen/JumpInstrTables.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/IR/Attributes.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/IR/Type.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-
-STATISTIC(NumCFIIndirectCalls,
- "Number of indirect call sites rewritten by the CFI pass");
-
-char ForwardControlFlowIntegrity::ID = 0;
-INITIALIZE_PASS_BEGIN(ForwardControlFlowIntegrity, "forward-cfi",
- "Control-Flow Integrity", true, true)
-INITIALIZE_PASS_DEPENDENCY(JumpInstrTableInfo);
-INITIALIZE_PASS_DEPENDENCY(JumpInstrTables);
-INITIALIZE_PASS_END(ForwardControlFlowIntegrity, "forward-cfi",
- "Control-Flow Integrity", true, true)
-
-ModulePass *llvm::createForwardControlFlowIntegrityPass() {
- return new ForwardControlFlowIntegrity();
-}
-
-ModulePass *llvm::createForwardControlFlowIntegrityPass(
- JumpTable::JumpTableType JTT, CFIntegrity CFIType, bool CFIEnforcing,
- StringRef CFIFuncName) {
- return new ForwardControlFlowIntegrity(JTT, CFIType, CFIEnforcing,
- CFIFuncName);
-}
-
-// Checks to see if a given CallSite is making an indirect call, including
-// cases where the indirect call is made through a bitcast.
-static bool isIndirectCall(CallSite &CS) {
- if (CS.getCalledFunction())
- return false;
-
- // Check the value to see if it is merely a bitcast of a function. In
- // this case, it will translate to a direct function call in the resulting
- // assembly, so we won't treat it as an indirect call here.
- const Value *V = CS.getCalledValue();
- if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
- return !(CE->isCast() && isa<Function>(CE->getOperand(0)));
- }
-
- // Otherwise, since we know it's a call, it must be an indirect call
- return true;
-}
-
-static const char cfi_failure_func_name[] = "__llvm_cfi_pointer_warning";
-
-ForwardControlFlowIntegrity::ForwardControlFlowIntegrity()
- : ModulePass(ID), IndirectCalls(), JTType(JumpTable::Single),
- CFIType(CFIntegrity::Sub), CFIEnforcing(false), CFIFuncName("") {
- initializeForwardControlFlowIntegrityPass(*PassRegistry::getPassRegistry());
-}
-
-ForwardControlFlowIntegrity::ForwardControlFlowIntegrity(
- JumpTable::JumpTableType JTT, CFIntegrity CFIType, bool CFIEnforcing,
- std::string CFIFuncName)
- : ModulePass(ID), IndirectCalls(), JTType(JTT), CFIType(CFIType),
- CFIEnforcing(CFIEnforcing), CFIFuncName(CFIFuncName) {
- initializeForwardControlFlowIntegrityPass(*PassRegistry::getPassRegistry());
-}
-
-ForwardControlFlowIntegrity::~ForwardControlFlowIntegrity() {}
-
-void ForwardControlFlowIntegrity::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<JumpInstrTableInfo>();
- AU.addRequired<JumpInstrTables>();
-}
-
-void ForwardControlFlowIntegrity::getIndirectCalls(Module &M) {
- // To get the indirect calls, we iterate over all functions and iterate over
- // the list of basic blocks in each. We extract a total list of indirect calls
- // before modifying any of them, since our modifications will modify the list
- // of basic blocks.
- for (Function &F : M) {
- for (BasicBlock &BB : F) {
- for (Instruction &I : BB) {
- CallSite CS(&I);
- if (!(CS && isIndirectCall(CS)))
- continue;
-
- Value *CalledValue = CS.getCalledValue();
-
- // Don't rewrite this instruction if the indirect call is actually just
- // inline assembly, since our transformation will generate an invalid
- // module in that case.
- if (isa<InlineAsm>(CalledValue))
- continue;
-
- IndirectCalls.push_back(&I);
- }
- }
- }
-}
-
-void ForwardControlFlowIntegrity::updateIndirectCalls(Module &M,
- CFITables &CFIT) {
- Type *Int64Ty = Type::getInt64Ty(M.getContext());
- for (Instruction *I : IndirectCalls) {
- CallSite CS(I);
- Value *CalledValue = CS.getCalledValue();
-
- // Get the function type for this call and look it up in the tables.
- Type *VTy = CalledValue->getType();
- PointerType *PTy = dyn_cast<PointerType>(VTy);
- Type *EltTy = PTy->getElementType();
- FunctionType *FunTy = dyn_cast<FunctionType>(EltTy);
- FunctionType *TransformedTy = JumpInstrTables::transformType(JTType, FunTy);
- ++NumCFIIndirectCalls;
- Constant *JumpTableStart = nullptr;
- Constant *JumpTableMask = nullptr;
- Constant *JumpTableSize = nullptr;
-
- // Some call sites have function types that don't correspond to any
- // address-taken function in the module. This happens when function pointers
- // are passed in from external code.
- auto it = CFIT.find(TransformedTy);
- if (it == CFIT.end()) {
- // In this case, make sure that the function pointer will change by
- // setting the mask and the start to be 0 so that the transformed
- // function is 0.
- JumpTableStart = ConstantInt::get(Int64Ty, 0);
- JumpTableMask = ConstantInt::get(Int64Ty, 0);
- JumpTableSize = ConstantInt::get(Int64Ty, 0);
- } else {
- JumpTableStart = it->second.StartValue;
- JumpTableMask = it->second.MaskValue;
- JumpTableSize = it->second.Size;
- }
-
- rewriteFunctionPointer(M, I, CalledValue, JumpTableStart, JumpTableMask,
- JumpTableSize);
- }
-
- return;
-}
-
-bool ForwardControlFlowIntegrity::runOnModule(Module &M) {
- JumpInstrTableInfo *JITI = &getAnalysis<JumpInstrTableInfo>();
- Type *Int64Ty = Type::getInt64Ty(M.getContext());
- Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
-
- // JumpInstrTableInfo stores information about the alignment of each entry.
- // The alignment returned by JumpInstrTableInfo is alignment in bytes, not
- // in the exponent.
- ByteAlignment = JITI->entryByteAlignment();
- LogByteAlignment = llvm::Log2_64(ByteAlignment);
-
- // Set up tables for control-flow integrity based on information about the
- // jump-instruction tables.
- CFITables CFIT;
- for (const auto &KV : JITI->getTables()) {
- uint64_t Size = static_cast<uint64_t>(KV.second.size());
- uint64_t TableSize = NextPowerOf2(Size);
-
- int64_t MaskValue = ((TableSize << LogByteAlignment) - 1) & -ByteAlignment;
- Constant *JumpTableMaskValue = ConstantInt::get(Int64Ty, MaskValue);
- Constant *JumpTableSize = ConstantInt::get(Int64Ty, Size);
-
- // The base of the table is defined to be the first jumptable function in
- // the table.
- Function *First = KV.second.begin()->second;
- Constant *JumpTableStartValue = ConstantExpr::getBitCast(First, VoidPtrTy);
- CFIT[KV.first].StartValue = JumpTableStartValue;
- CFIT[KV.first].MaskValue = JumpTableMaskValue;
- CFIT[KV.first].Size = JumpTableSize;
- }
-
- if (CFIT.empty())
- return false;
-
- getIndirectCalls(M);
-
- if (!CFIEnforcing) {
- addWarningFunction(M);
- }
-
- // Update the instructions with the check and the indirect jump through our
- // table.
- updateIndirectCalls(M, CFIT);
-
- return true;
-}
-
-void ForwardControlFlowIntegrity::addWarningFunction(Module &M) {
- PointerType *CharPtrTy = Type::getInt8PtrTy(M.getContext());
-
- // Get the type of the Warning Function: void (i8*, i8*),
- // where the first argument is the name of the function in which the violation
- // occurs, and the second is the function pointer that violates CFI.
- SmallVector<Type *, 2> WarningFunArgs;
- WarningFunArgs.push_back(CharPtrTy);
- WarningFunArgs.push_back(CharPtrTy);
- FunctionType *WarningFunTy =
- FunctionType::get(Type::getVoidTy(M.getContext()), WarningFunArgs, false);
-
- if (!CFIFuncName.empty()) {
- Constant *FailureFun = M.getOrInsertFunction(CFIFuncName, WarningFunTy);
- if (!FailureFun)
- report_fatal_error("Could not get or insert the function specified by"
- " -cfi-func-name");
- } else {
- // The default warning function swallows the warning and lets the call
- // continue, since there's no generic way for it to print out this
- // information.
- Function *WarningFun = M.getFunction(cfi_failure_func_name);
- if (!WarningFun) {
- WarningFun =
- Function::Create(WarningFunTy, GlobalValue::LinkOnceAnyLinkage,
- cfi_failure_func_name, &M);
- }
-
- BasicBlock *Entry =
- BasicBlock::Create(M.getContext(), "entry", WarningFun, 0);
- ReturnInst::Create(M.getContext(), Entry);
- }
-}
-
-void ForwardControlFlowIntegrity::rewriteFunctionPointer(
- Module &M, Instruction *I, Value *FunPtr, Constant *JumpTableStart,
- Constant *JumpTableMask, Constant *JumpTableSize) {
- IRBuilder<> TempBuilder(I);
-
- Type *OrigFunType = FunPtr->getType();
-
- BasicBlock *CurBB = cast<BasicBlock>(I->getParent());
- Function *CurF = cast<Function>(CurBB->getParent());
- Type *Int64Ty = Type::getInt64Ty(M.getContext());
-
- Value *TI = TempBuilder.CreatePtrToInt(FunPtr, Int64Ty);
- Value *TStartInt = TempBuilder.CreatePtrToInt(JumpTableStart, Int64Ty);
-
- Value *NewFunPtr = nullptr;
- Value *Check = nullptr;
- switch (CFIType) {
- case CFIntegrity::Sub: {
- // This is the subtract, mask, and add version.
- // Subtract from the base.
- Value *Sub = TempBuilder.CreateSub(TI, TStartInt);
-
- // Mask the difference to force this to be a table offset.
- Value *And = TempBuilder.CreateAnd(Sub, JumpTableMask);
-
- // Add it back to the base.
- Value *Result = TempBuilder.CreateAdd(And, TStartInt);
-
- // Convert it back into a function pointer that we can call.
- NewFunPtr = TempBuilder.CreateIntToPtr(Result, OrigFunType);
- break;
- }
- case CFIntegrity::Ror: {
- // This is the subtract and rotate version.
- // Rotate right by the alignment value. The optimizer should recognize
- // this sequence as a rotation.
-
- // This cast is safe, since unsigned is always a subset of uint64_t.
- uint64_t LogByteAlignment64 = static_cast<uint64_t>(LogByteAlignment);
- Constant *RightShift = ConstantInt::get(Int64Ty, LogByteAlignment64);
- Constant *LeftShift = ConstantInt::get(Int64Ty, 64 - LogByteAlignment64);
-
- // Subtract from the base.
- Value *Sub = TempBuilder.CreateSub(TI, TStartInt);
-
- // Create the equivalent of a rotate-right instruction.
- Value *Shr = TempBuilder.CreateLShr(Sub, RightShift);
- Value *Shl = TempBuilder.CreateShl(Sub, LeftShift);
- Value *Or = TempBuilder.CreateOr(Shr, Shl);
-
- // Perform unsigned comparison to check for inclusion in the table.
- Check = TempBuilder.CreateICmpULT(Or, JumpTableSize);
- NewFunPtr = FunPtr;
- break;
- }
- case CFIntegrity::Add: {
- // This is the mask and add version.
- // Mask the function pointer to turn it into an offset into the table.
- Value *And = TempBuilder.CreateAnd(TI, JumpTableMask);
-
- // Then or this offset to the base and get the pointer value.
- Value *Result = TempBuilder.CreateAdd(And, TStartInt);
-
- // Convert it back into a function pointer that we can call.
- NewFunPtr = TempBuilder.CreateIntToPtr(Result, OrigFunType);
- break;
- }
- }
-
- if (!CFIEnforcing) {
- // If a check hasn't been added (in the rotation version), then check to see
- // if it's the same as the original function. This check determines whether
- // or not we call the CFI failure function.
- if (!Check)
- Check = TempBuilder.CreateICmpEQ(NewFunPtr, FunPtr);
- BasicBlock *InvalidPtrBlock =
- BasicBlock::Create(M.getContext(), "invalid.ptr", CurF, 0);
- BasicBlock *ContinuationBB = CurBB->splitBasicBlock(I);
-
- // Remove the unconditional branch that connects the two blocks.
- TerminatorInst *TermInst = CurBB->getTerminator();
- TermInst->eraseFromParent();
-
- // Add a conditional branch that depends on the Check above.
- BranchInst::Create(ContinuationBB, InvalidPtrBlock, Check, CurBB);
-
- // Call the warning function for this pointer, then continue.
- Instruction *BI = BranchInst::Create(ContinuationBB, InvalidPtrBlock);
- insertWarning(M, InvalidPtrBlock, BI, FunPtr);
- } else {
- // Modify the instruction to call this value.
- CallSite CS(I);
- CS.setCalledFunction(NewFunPtr);
- }
-}
-
-void ForwardControlFlowIntegrity::insertWarning(Module &M, BasicBlock *Block,
- Instruction *I, Value *FunPtr) {
- Function *ParentFun = cast<Function>(Block->getParent());
-
- // Get the function to call right before the instruction.
- Function *WarningFun = nullptr;
- if (CFIFuncName.empty()) {
- WarningFun = M.getFunction(cfi_failure_func_name);
- } else {
- WarningFun = M.getFunction(CFIFuncName);
- }
-
- assert(WarningFun && "Could not find the CFI failure function");
-
- Type *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
-
- IRBuilder<> WarningInserter(I);
- // Create a mergeable GlobalVariable containing the name of the function.
- Value *ParentNameGV =
- WarningInserter.CreateGlobalString(ParentFun->getName());
- Value *ParentNamePtr = WarningInserter.CreateBitCast(ParentNameGV, VoidPtrTy);
- Value *FunVoidPtr = WarningInserter.CreateBitCast(FunPtr, VoidPtrTy);
- WarningInserter.CreateCall2(WarningFun, ParentNamePtr, FunVoidPtr);
-}
+++ /dev/null
-//===-- JumpInstrTables.cpp: Jump-Instruction Tables ----------------------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief An implementation of jump-instruction tables.
-///
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "jt"
-
-#include "llvm/CodeGen/JumpInstrTables.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/JumpInstrTableInfo.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/IR/Attributes.h"
-#include "llvm/IR/CallSite.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/IR/Type.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include <vector>
-
-using namespace llvm;
-
-char JumpInstrTables::ID = 0;
-
-INITIALIZE_PASS_BEGIN(JumpInstrTables, "jump-instr-tables",
- "Jump-Instruction Tables", true, true)
-INITIALIZE_PASS_DEPENDENCY(JumpInstrTableInfo);
-INITIALIZE_PASS_END(JumpInstrTables, "jump-instr-tables",
- "Jump-Instruction Tables", true, true)
-
-STATISTIC(NumJumpTables, "Number of indirect call tables generated");
-STATISTIC(NumFuncsInJumpTables, "Number of functions in the jump tables");
-
-ModulePass *llvm::createJumpInstrTablesPass() {
- // The default implementation uses a single table for all functions.
- return new JumpInstrTables(JumpTable::Single);
-}
-
-ModulePass *llvm::createJumpInstrTablesPass(JumpTable::JumpTableType JTT) {
- return new JumpInstrTables(JTT);
-}
-
-namespace {
-static const char jump_func_prefix[] = "__llvm_jump_instr_table_";
-static const char jump_section_prefix[] = ".jump.instr.table.text.";
-
-// Checks to see if a given CallSite is making an indirect call, including
-// cases where the indirect call is made through a bitcast.
-bool isIndirectCall(CallSite &CS) {
- if (CS.getCalledFunction())
- return false;
-
- // Check the value to see if it is merely a bitcast of a function. In
- // this case, it will translate to a direct function call in the resulting
- // assembly, so we won't treat it as an indirect call here.
- const Value *V = CS.getCalledValue();
- if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
- return !(CE->isCast() && isa<Function>(CE->getOperand(0)));
- }
-
- // Otherwise, since we know it's a call, it must be an indirect call
- return true;
-}
-
-// Replaces Functions and GlobalAliases with a different Value.
-bool replaceGlobalValueIndirectUse(GlobalValue *GV, Value *V, Use *U) {
- User *Us = U->getUser();
- if (!Us)
- return false;
- if (Instruction *I = dyn_cast<Instruction>(Us)) {
- CallSite CS(I);
-
- // Don't do the replacement if this use is a direct call to this function.
- // If the use is not the called value, then replace it.
- if (CS && (isIndirectCall(CS) || CS.isCallee(U))) {
- return false;
- }
-
- U->set(V);
- } else if (Constant *C = dyn_cast<Constant>(Us)) {
- // Don't replace calls to bitcasts of function symbols, since they get
- // translated to direct calls.
- if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Us)) {
- if (CE->getOpcode() == Instruction::BitCast) {
- // This bitcast must have exactly one user.
- if (CE->user_begin() != CE->user_end()) {
- User *ParentUs = *CE->user_begin();
- if (CallInst *CI = dyn_cast<CallInst>(ParentUs)) {
- CallSite CS(CI);
- Use &CEU = *CE->use_begin();
- if (CS.isCallee(&CEU)) {
- return false;
- }
- }
- }
- }
- }
-
- // GlobalAlias doesn't support replaceUsesOfWithOnConstant. And the verifier
- // requires alias to point to a defined function. So, GlobalAlias is handled
- // as a separate case in runOnModule.
- if (!isa<GlobalAlias>(C))
- C->replaceUsesOfWithOnConstant(GV, V, U);
- } else {
- llvm_unreachable("The Use of a Function symbol is neither an instruction "
- "nor a constant");
- }
-
- return true;
-}
-
-// Replaces all replaceable address-taken uses of GV with a pointer to a
-// jump-instruction table entry.
-void replaceValueWithFunction(GlobalValue *GV, Function *F) {
- // Go through all uses of this function and replace the uses of GV with the
- // jump-table version of the function. Get the uses as a vector before
- // replacing them, since replacing them changes the use list and invalidates
- // the iterator otherwise.
- for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E;) {
- Use &U = *I++;
-
- // Replacement of constants replaces all instances in the constant. So, some
- // uses might have already been handled by the time we reach them here.
- if (U.get() == GV)
- replaceGlobalValueIndirectUse(GV, F, &U);
- }
-
- return;
-}
-} // end anonymous namespace
-
-JumpInstrTables::JumpInstrTables()
- : ModulePass(ID), Metadata(), JITI(nullptr), TableCount(0),
- JTType(JumpTable::Single) {
- initializeJumpInstrTablesPass(*PassRegistry::getPassRegistry());
-}
-
-JumpInstrTables::JumpInstrTables(JumpTable::JumpTableType JTT)
- : ModulePass(ID), Metadata(), JITI(nullptr), TableCount(0), JTType(JTT) {
- initializeJumpInstrTablesPass(*PassRegistry::getPassRegistry());
-}
-
-JumpInstrTables::~JumpInstrTables() {}
-
-void JumpInstrTables::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<JumpInstrTableInfo>();
-}
-
-Function *JumpInstrTables::insertEntry(Module &M, Function *Target) {
- FunctionType *OrigFunTy = Target->getFunctionType();
- FunctionType *FunTy = transformType(JTType, OrigFunTy);
-
- JumpMap::iterator it = Metadata.find(FunTy);
- if (Metadata.end() == it) {
- struct TableMeta Meta;
- Meta.TableNum = TableCount;
- Meta.Count = 0;
- Metadata[FunTy] = Meta;
- it = Metadata.find(FunTy);
- ++NumJumpTables;
- ++TableCount;
- }
-
- it->second.Count++;
-
- std::string NewName(jump_func_prefix);
- NewName += (Twine(it->second.TableNum) + "_" + Twine(it->second.Count)).str();
- Function *JumpFun =
- Function::Create(OrigFunTy, GlobalValue::ExternalLinkage, NewName, &M);
- // The section for this table
- JumpFun->setSection((jump_section_prefix + Twine(it->second.TableNum)).str());
- JITI->insertEntry(FunTy, Target, JumpFun);
-
- ++NumFuncsInJumpTables;
- return JumpFun;
-}
-
-bool JumpInstrTables::hasTable(FunctionType *FunTy) {
- FunctionType *TransTy = transformType(JTType, FunTy);
- return Metadata.end() != Metadata.find(TransTy);
-}
-
-FunctionType *JumpInstrTables::transformType(JumpTable::JumpTableType JTT,
- FunctionType *FunTy) {
- // Returning nullptr forces all types into the same table, since all types map
- // to the same type
- Type *VoidPtrTy = Type::getInt8PtrTy(FunTy->getContext());
-
- // Ignore the return type.
- Type *RetTy = VoidPtrTy;
- bool IsVarArg = FunTy->isVarArg();
- std::vector<Type *> ParamTys(FunTy->getNumParams());
- FunctionType::param_iterator PI, PE;
- int i = 0;
-
- std::vector<Type *> EmptyParams;
- Type *Int32Ty = Type::getInt32Ty(FunTy->getContext());
- FunctionType *VoidFnTy = FunctionType::get(
- Type::getVoidTy(FunTy->getContext()), EmptyParams, false);
- switch (JTT) {
- case JumpTable::Single:
-
- return FunctionType::get(RetTy, EmptyParams, false);
- case JumpTable::Arity:
- // Transform all types to void* so that all functions with the same arity
- // end up in the same table.
- for (PI = FunTy->param_begin(), PE = FunTy->param_end(); PI != PE;
- PI++, i++) {
- ParamTys[i] = VoidPtrTy;
- }
-
- return FunctionType::get(RetTy, ParamTys, IsVarArg);
- case JumpTable::Simplified:
- // Project all parameters types to one of 3 types: composite, integer, and
- // function, matching the three subclasses of Type.
- for (PI = FunTy->param_begin(), PE = FunTy->param_end(); PI != PE;
- ++PI, ++i) {
- assert((isa<IntegerType>(*PI) || isa<FunctionType>(*PI) ||
- isa<CompositeType>(*PI)) &&
- "This type is not an Integer or a Composite or a Function");
- if (isa<CompositeType>(*PI)) {
- ParamTys[i] = VoidPtrTy;
- } else if (isa<FunctionType>(*PI)) {
- ParamTys[i] = VoidFnTy;
- } else if (isa<IntegerType>(*PI)) {
- ParamTys[i] = Int32Ty;
- }
- }
-
- return FunctionType::get(RetTy, ParamTys, IsVarArg);
- case JumpTable::Full:
- // Don't transform this type at all.
- return FunTy;
- }
-
- return nullptr;
-}
-
-bool JumpInstrTables::runOnModule(Module &M) {
- JITI = &getAnalysis<JumpInstrTableInfo>();
-
- // Get the set of jumptable-annotated functions that have their address taken.
- DenseMap<Function *, Function *> Functions;
- for (Function &F : M) {
- if (F.hasFnAttribute(Attribute::JumpTable) && F.hasAddressTaken()) {
- assert(F.hasUnnamedAddr() &&
- "Attribute 'jumptable' requires 'unnamed_addr'");
- Functions[&F] = nullptr;
- }
- }
-
- // Create the jump-table functions.
- for (auto &KV : Functions) {
- Function *F = KV.first;
- KV.second = insertEntry(M, F);
- }
-
- // GlobalAlias is a special case, because the target of an alias statement
- // must be a defined function. So, instead of replacing a given function in
- // the alias, we replace all uses of aliases that target jumptable functions.
- // Note that there's no need to create these functions, since only aliases
- // that target known jumptable functions are replaced, and there's no way to
- // put the jumptable annotation on a global alias.
- DenseMap<GlobalAlias *, Function *> Aliases;
- for (GlobalAlias &GA : M.aliases()) {
- Constant *Aliasee = GA.getAliasee();
- if (Function *F = dyn_cast<Function>(Aliasee)) {
- auto it = Functions.find(F);
- if (it != Functions.end()) {
- Aliases[&GA] = it->second;
- }
- }
- }
-
- // Replace each address taken function with its jump-instruction table entry.
- for (auto &KV : Functions)
- replaceValueWithFunction(KV.first, KV.second);
-
- for (auto &KV : Aliases)
- replaceValueWithFunction(KV.first, KV.second);
-
- return !Functions.empty();
-}
//===----------------------------------------------------------------------===//
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Analysis/JumpInstrTableInfo.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/BasicTTIImpl.h"
-#include "llvm/CodeGen/ForwardControlFlowIntegrity.h"
-#include "llvm/CodeGen/JumpInstrTables.h"
#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/Passes.h"
bool DisableVerify,
AnalysisID StartAfter,
AnalysisID StopAfter) {
- // Passes to handle jumptable function annotations. These can't be handled at
- // JIT time, so we don't add them directly to addPassesToGenerateCode.
- PM.add(createJumpInstrTableInfoPass(
- getSubtargetImpl()->getInstrInfo()->getJumpInstrTableEntryBound()));
- PM.add(createJumpInstrTablesPass(Options.JTType));
- if (Options.FCFI)
- PM.add(createForwardControlFlowIntegrityPass(
- Options.JTType, Options.CFIType, Options.CFIEnforcing,
- Options.getCFIFuncName()));
-
// Add common CodeGen passes.
MCContext *Context = addPassesToGenerateCode(this, PM, DisableVerify,
StartAfter, StopAfter);
; STOP: Loop Strength Reduction
; STOP-NEXT: Machine Function Analysis
-; START: -machine-branch-prob -jump-instr-tables -gc-lowering
+; START: -machine-branch-prob -gc-lowering
; START: FunctionPass Manager
; START-NEXT: Lower Garbage Collection Instructions
+++ /dev/null
-; RUN: llc -mtriple=i386-unknown-linux-gnu -fcfi -cfi-enforcing <%s | FileCheck --check-prefix=X86 %s
-; RUN: llc -mtriple=x86_64-unknown-linux-gnu -fcfi -cfi-enforcing <%s | FileCheck --check-prefix=X86-64 %s
-
-define void @indirect_fun() unnamed_addr jumptable {
- ret void
-}
-
-define i32 @m(void ()* %fun) {
- call void ()* %fun()
-; CHECK: subl
-; X86-64: andq $8,
-; X86-64: leaq __llvm_jump_instr_table_0_1({{%[a-z0-9]+}}), [[REG:%[a-z0-9]+]]
-; X86-64-NOT: callq __llvm_cfi_pointer_warning
-; X86-64: callq *[[REG]]
-; X86: andl $8,
-; X86: leal __llvm_jump_instr_table_0_1({{%[a-z0-9]+}}), [[REG:%[a-z0-9]+]]
-; X86-NOT: calll __llvm_cfi_pointer_warning
-; X86: calll *[[REG]]
- ret i32 0
-}
-
-define void ()* @get_fun() {
- ret void ()* @indirect_fun
-}
-
-define i32 @main(i32 %argc, i8** %argv) {
- %f = call void ()* ()* @get_fun()
- %a = call i32 @m(void ()* %f)
- ret i32 %a
-}
-
-; CHECK: .align 8
-; CHECK: __llvm_jump_instr_table_0_1:
-; CHECK: jmp indirect_fun@PLT
+++ /dev/null
-; RUN: llc <%s -fcfi -cfi-type=sub | FileCheck %s
-; ModuleID = 'test.cc'
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-declare i32 @__gxx_personality_v0(...)
-
-@_ZTIPKc = external constant i8*
-@_ZTIi = external constant i8*
-
-define void @f() unnamed_addr jumptable {
- ret void
-}
-
-@a = global void ()* @f
-
-; Make sure invoke gets targeted as well as regular calls
-define void @_Z3foov(void ()* %f) uwtable ssp {
-; CHECK-LABEL: _Z3foov:
- entry:
- invoke void %f()
- to label %try.cont unwind label %lpad
-; CHECK: callq __llvm_cfi_pointer_warning
-; CHECK: callq *%rbx
-
- lpad:
- %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- catch i8* bitcast (i8** @_ZTIi to i8*)
- filter [1 x i8*] [i8* bitcast (i8** @_ZTIPKc to i8*)]
- ret void
-
- try.cont:
- ret void
-}
-
+++ /dev/null
-; RUN: llc -fcfi -cfi-func-name=cfi_new_failure <%s | FileCheck %s
-
-target triple = "x86_64-unknown-linux-gnu"
-define void @indirect_fun() unnamed_addr jumptable {
- ret void
-}
-
-define i32 @m(void ()* %fun) {
-; CHECK-LABEL: @m
- call void ()* %fun()
-; CHECK: callq cfi_new_failure
- ret i32 0
-}
-
-define void ()* @get_fun() {
- ret void ()* @indirect_fun
-}
-
-define i32 @main(i32 %argc, i8** %argv) {
- %f = call void ()* ()* @get_fun()
- %a = call i32 @m(void ()* %f)
- ret i32 %a
-}
-
-; CHECK: .align 8
-; CHECK: __llvm_jump_instr_table_0_1:
-; CHECK: jmp indirect_fun@PLT
+++ /dev/null
-; RUN: llc -fcfi -cfi-type=sub <%s | FileCheck --check-prefix=SUB %s
-; RUN: llc -fcfi -cfi-type=add <%s | FileCheck --check-prefix=ADD %s
-; RUN: llc -fcfi -cfi-type=ror <%s | FileCheck --check-prefix=ROR %s
-
-target triple = "x86_64-unknown-linux-gnu"
-
-define void @indirect_fun() unnamed_addr jumptable {
- ret void
-}
-
-define i32 @m(void ()* %fun) {
- call void ()* %fun()
-; SUB: subl
-; SUB: andq $8
-; SUB-LABEL: leaq __llvm_jump_instr_table_0_1
-; SUB-LABEL: callq __llvm_cfi_pointer_warning
-
-; ROR: subq
-; ROR: rolq $61
-; ROR: testq
-; ROR-LABEL: callq __llvm_cfi_pointer_warning
-
-; ADD: andq $8
-; ADD-LABEL: leaq __llvm_jump_instr_table_0_1
-; ADD: cmpq
-; ADD-LABEL: callq __llvm_cfi_pointer_warning
-ret i32 0
-}
-
-define void ()* @get_fun() {
- ret void ()* @indirect_fun
-}
-
-define i32 @main(i32 %argc, i8** %argv) {
- %f = call void ()* ()* @get_fun()
- %a = call i32 @m(void ()* %f)
- ret i32 %a
-}
-; SUB: .text
-; SUB: .align 8
-; SUB-LABEL: .type __llvm_jump_instr_table_0_1,@function
-; SUB-LABEL:__llvm_jump_instr_table_0_1:
-; SUB-LABEL: jmp indirect_fun@PLT
+++ /dev/null
-; RUN: llc <%s -jump-table-type=single | FileCheck %s
-target triple = "x86_64-unknown-linux-gnu"
-define i32 @f() unnamed_addr jumptable {
-entry:
- ret i32 0
-}
-
-@i = internal alias i32 ()* @f
-@j = alias i32 ()* @f
-
-define i32 @main(i32 %argc, i8** %argv) {
- %temp = alloca i32 ()*, align 8
- store i32 ()* @i, i32()** %temp, align 8
-; CHECK: movq $__llvm_jump_instr_table_0_1
- %1 = load i32 ()** %temp, align 8
-; CHECK: movl $__llvm_jump_instr_table_0_1
- %2 = call i32 ()* %1()
- %3 = call i32 ()* @i()
-; CHECK: callq i
- %4 = call i32 ()* @j()
-; CHECK: callq j
- ret i32 %3
-}
-
-; There should only be one table, even though there are two GlobalAliases,
-; because they both alias the same value.
-
-; CHECK: .align 8, 0x90
-; CHECK: .type __llvm_jump_instr_table_0_1,@function
-; CHECK: __llvm_jump_instr_table_0_1:
-; CHECK: jmp f@PLT
-
+++ /dev/null
-; RUN: llc -filetype=obj <%s -jump-table-type=single -o %t1
-; RUN: llvm-objdump -triple=x86_64-unknown-linux-gnu -d %t1 | FileCheck %s
-target triple = "x86_64-unknown-linux-gnu"
-define i32 @f() unnamed_addr jumptable {
- ret i32 0
-}
-
-define i32 @g(i8* %a) unnamed_addr jumptable {
- ret i32 0
-}
-
-define void @h(void ()* %func) unnamed_addr jumptable {
- ret void
-}
-
-define i32 @main() {
- %g = alloca i32 (...)*, align 8
- store i32 (...)* bitcast (i32 ()* @f to i32 (...)*), i32 (...)** %g, align 8
- %1 = load i32 (...)** %g, align 8
- %call = call i32 (...)* %1()
- call void (void ()*)* @h(void ()* bitcast (void (void ()*)* @h to void ()*))
- %a = call i32 (i32*)* bitcast (i32 (i8*)* @g to i32(i32*)*)(i32* null)
- ret i32 %a
-}
-
-; Make sure that the padding from getJumpInstrTableEntryBound is right.
-; CHECK: __llvm_jump_instr_table_0_1:
-; CHECK-NEXT: e9 00 00 00 00 jmp 0
-; CHECK-NEXT: 0f 1f 00 nopl (%rax)
+++ /dev/null
-; RUN: llc <%s -jump-table-type=single | FileCheck %s
-target triple = "x86_64-unknown-linux-gnu"
-define i32 @f() unnamed_addr jumptable {
- ret i32 0
-}
-
-define i32 @g(i8* %a) unnamed_addr jumptable {
- ret i32 0
-}
-
-define void @h(void ()* %func) unnamed_addr jumptable {
- ret void
-}
-
-define i32 @main() {
- %g = alloca i32 (...)*, align 8
- store i32 (...)* bitcast (i32 ()* @f to i32 (...)*), i32 (...)** %g, align 8
-; CHECK: movq $__llvm_jump_instr_table_0_[[ENTRY:1|2|3]],
-; CHECK: movl $__llvm_jump_instr_table_0_[[ENTRY]],
- %1 = load i32 (...)** %g, align 8
- %call = call i32 (...)* %1()
- call void (void ()*)* @h(void ()* bitcast (void (void ()*)* @h to void ()*))
-; CHECK: movl $__llvm_jump_instr_table_0_{{1|2|3}},
-; CHECK: callq h
-
- %a = call i32 (i32*)* bitcast (i32 (i8*)* @g to i32(i32*)*)(i32* null)
-; CHECK: callq g
- ret i32 %a
-}
-
-; CHECK: .align 8, 0x90
-; CHECK: .type __llvm_jump_instr_table_0_1,@function
-; CHECK: __llvm_jump_instr_table_0_1:
-; CHECK: jmp {{f|g|h}}@PLT
-; CHECK: .align 8, 0x90
-; CHECK: .type __llvm_jump_instr_table_0_2,@function
-; CHECK: __llvm_jump_instr_table_0_2:
-; CHECK: jmp {{f|g|h}}@PLT
-; CHECK: .align 8, 0x90
-; CHECK: .type __llvm_jump_instr_table_0_3,@function
-; CHECK: __llvm_jump_instr_table_0_3:
-; CHECK: jmp {{f|g|h}}@PLT
-
+++ /dev/null
-; RUN: llc <%s -jump-table-type=single | FileCheck --check-prefix=SINGLE %s
-; RUN: llc <%s -jump-table-type=arity | FileCheck --check-prefix=ARITY %s
-; RUN: llc <%s -jump-table-type=simplified | FileCheck --check-prefix=SIMPL %s
-; RUN: llc <%s -jump-table-type=full | FileCheck --check-prefix=FULL %s
-
-target triple = "x86_64-unknown-linux-gnu"
-
-%struct.fun_struct = type { i32 (...)* }
-
-@a = global [12 x i32 () *] [ i32 ()* bitcast (void ()* @indirect_fun to i32 ()*),
- i32 ()* bitcast (void ()* @indirect_fun_match to i32 ()*),
- i32 ()* bitcast (i32 ()* @indirect_fun_i32 to i32 ()*),
- i32 ()* bitcast (i32 (i32)* @indirect_fun_i32_1 to i32 ()*),
- i32 ()* bitcast (i32 (i32, i32)* @indirect_fun_i32_2 to i32 ()*),
- i32 ()* bitcast (i32* (i32*, i32)* @indirect_fun_i32S_2 to i32 ()*),
- i32 ()* bitcast (void (%struct.fun_struct)* @indirect_fun_struct to i32 ()*),
- i32 ()* bitcast (void (i32 (...)*, i32)* @indirect_fun_fun to i32 ()*),
- i32 ()* bitcast (i32 (i32 (...)*, i32)* @indirect_fun_fun_ret to i32 ()*),
- i32 ()* bitcast (void ([19 x i8])* @indirect_fun_array to i32 ()*),
- i32 ()* bitcast (void (<3 x i32>)* @indirect_fun_vec to i32 ()*),
- i32 ()* bitcast (void (<4 x float>)* @indirect_fun_vec_2 to i32 ()*)
- ]
-
-define void @indirect_fun() unnamed_addr jumptable {
- ret void
-}
-
-define void @indirect_fun_match() unnamed_addr jumptable {
- ret void
-}
-
-define i32 @indirect_fun_i32() unnamed_addr jumptable {
- ret i32 0
-}
-
-define i32 @indirect_fun_i32_1(i32 %a) unnamed_addr jumptable {
- ret i32 %a
-}
-
-define i32 @indirect_fun_i32_2(i32 %a, i32 %b) unnamed_addr jumptable {
- ret i32 %a
-}
-
-define i32* @indirect_fun_i32S_2(i32* %a, i32 %b) unnamed_addr jumptable {
- ret i32* %a
-}
-
-define void @indirect_fun_struct(%struct.fun_struct %fs) unnamed_addr jumptable {
- ret void
-}
-
-define void @indirect_fun_fun(i32 (...)* %fun, i32 %a) unnamed_addr jumptable {
- ret void
-}
-
-define i32 @indirect_fun_fun_ret(i32 (...)* %fun, i32 %a) unnamed_addr jumptable {
- ret i32 %a
-}
-
-define void @indirect_fun_array([19 x i8] %a) unnamed_addr jumptable {
- ret void
-}
-
-define void @indirect_fun_vec(<3 x i32> %a) unnamed_addr jumptable {
- ret void
-}
-
-define void @indirect_fun_vec_2(<4 x float> %a) unnamed_addr jumptable {
- ret void
-}
-
-define i32 @m(void ()* %fun) {
- call void ()* %fun()
- ret i32 0
-}
-
-define void ()* @get_fun() {
- ret void ()* @indirect_fun
-; SINGLE: movl $__llvm_jump_instr_table_0_
-; ARITY: movl $__llvm_jump_instr_table_
-; SIMPL: movl $__llvm_jump_instr_table_
-; FULL: movl $__llvm_jump_instr_table_
-}
-
-define i32 @main(i32 %argc, i8** %argv) {
- %f = call void ()* ()* @get_fun()
- %a = call i32 @m(void ()* %f)
- ret i32 %a
-}
-
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_1,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_1:
-; SINGLE-DAG: jmp indirect_fun_array@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_2,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_2:
-; SINGLE-DAG: jmp indirect_fun_i32_2@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_3,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_3:
-; SINGLE-DAG: jmp indirect_fun_vec_2@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_4,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_4:
-; SINGLE-DAG: jmp indirect_fun_i32S_2@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_5,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_5:
-; SINGLE-DAG: jmp indirect_fun_struct@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_6,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_6:
-; SINGLE-DAG: jmp indirect_fun_i32_1@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_7,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_7:
-; SINGLE-DAG: jmp indirect_fun_i32@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_8,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_8:
-; SINGLE-DAG: jmp indirect_fun_fun@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_9,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_9:
-; SINGLE-DAG: jmp indirect_fun_fun_ret@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_10,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_10:
-; SINGLE-DAG: jmp indirect_fun@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_11,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_11:
-; SINGLE-DAG: jmp indirect_fun_match@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: .type __llvm_jump_instr_table_0_12,@function
-; SINGLE-DAG: __llvm_jump_instr_table_0_12:
-; SINGLE-DAG: jmp indirect_fun_vec@PLT
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: ud2
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: ud2
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: ud2
-; SINGLE-DAG: .align 8, 0x90
-; SINGLE-DAG: ud2
-
-
-; ARITY-DAG: .align 8, 0x90
-; ARITY-DAG: .type __llvm_jump_instr_table_2_1,@function
-; ARITY-DAG: __llvm_jump_instr_table_2_1:
-; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
-; ARITY-DAG: .align 8, 0x90
-; ARITY-DAG: ud2
-; ARITY-DAG: .align 8, 0x90
-; ARITY-DAG: .type __llvm_jump_instr_table_0_1,@function
-; ARITY-DAG: __llvm_jump_instr_table_0_1:
-; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
-; ARITY-DAG: .align 8, 0x90
-; ARITY-DAG: .type __llvm_jump_instr_table_1_1,@function
-; ARITY-DAG: __llvm_jump_instr_table_1_1:
-; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
-
-; SIMPL-DAG: .align 8, 0x90
-; SIMPL-DAG: .type __llvm_jump_instr_table_2_1,@function
-; SIMPL-DAG: __llvm_jump_instr_table_2_1:
-; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
-; SIMPL-DAG: .align 8, 0x90
-; SIMPL-DAG: ud2
-; SIMPL-DAG: .align 8, 0x90
-; SIMPL-DAG: .type __llvm_jump_instr_table_0_1,@function
-; SIMPL-DAG: __llvm_jump_instr_table_0_1:
-; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
-; SIMPL-DAG: .align 8, 0x90
-; SIMPL-DAG: .type __llvm_jump_instr_table_1_1,@function
-; SIMPL-DAG: __llvm_jump_instr_table_1_1:
-; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
-; SIMPL-DAG: .align 8, 0x90
-; SIMPL-DAG: .type __llvm_jump_instr_table_3_1,@function
-; SIMPL-DAG: __llvm_jump_instr_table_3_1:
-; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
-; SIMPL-DAG: .align 8, 0x90
-; SIMPL-DAG: .type __llvm_jump_instr_table_4_1,@function
-; SIMPL-DAG: __llvm_jump_instr_table_4_1:
-; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
-
-
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_10_1,@function
-; FULL-DAG:__llvm_jump_instr_table_10_1:
-; FULL-DAG: jmp indirect_fun_i32_1@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_9_1,@function
-; FULL-DAG:__llvm_jump_instr_table_9_1:
-; FULL-DAG: jmp indirect_fun_i32_2@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_7_1,@function
-; FULL-DAG:__llvm_jump_instr_table_7_1:
-; FULL-DAG: jmp indirect_fun_i32S_2@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_3_1,@function
-; FULL-DAG:__llvm_jump_instr_table_3_1:
-; FULL-DAG: jmp indirect_fun_vec_2@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_2_1,@function
-; FULL-DAG:__llvm_jump_instr_table_2_1:
-; FULL-DAG: jmp indirect_fun@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_8_1,@function
-; FULL-DAG:__llvm_jump_instr_table_8_1:
-; FULL-DAG: jmp indirect_fun_i32@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_1_1,@function
-; FULL-DAG:__llvm_jump_instr_table_1_1:
-; FULL-DAG: jmp indirect_fun_array@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_0_1,@function
-; FULL-DAG:__llvm_jump_instr_table_0_1:
-; FULL-DAG: jmp indirect_fun_vec@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_6_1,@function
-; FULL-DAG:__llvm_jump_instr_table_6_1:
-; FULL-DAG: jmp indirect_fun_struct@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_5_1,@function
-; FULL-DAG:__llvm_jump_instr_table_5_1:
-; FULL-DAG: jmp indirect_fun_fun@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: .type __llvm_jump_instr_table_4_1,@function
-; FULL-DAG:__llvm_jump_instr_table_4_1:
-; FULL-DAG: jmp indirect_fun_fun_ret@PLT
-; FULL-DAG: .align 8, 0x90
-; FULL-DAG: ud2
+++ /dev/null
-; RUN: llvm-as <%s >%t1
-; RUN: llvm-lto -o %t2 %t1 -jump-table-type=arity
-; RUN: llvm-nm %t2 | FileCheck %s
-
-; CHECK: t __llvm_jump_instr_table_0_1
-; CHECK: t __llvm_jump_instr_table_1_1
-
-target triple = "x86_64-unknown-linux-gnu"
-
-define i32 @g(i32 %a) unnamed_addr jumptable {
- ret i32 %a
-}
-
-define i32 @f() unnamed_addr jumptable {
- ret i32 0
-}
-
-define i32 @main() {
- ret i32 0
-}
-
-@llvm.used = appending global [2 x i8*] [i8* bitcast (i32(i32)* @g to i8*),
- i8* bitcast (i32()* @f to i8*)]