diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -420,6 +420,7 @@ void emitBBAddrMapSection(const MachineFunction &MF); void emitKCFITrapEntry(const MachineFunction &MF, const MCSymbol *Symbol); + bool needsKCFITypeId(const MachineFunction &MF); virtual void emitKCFITypeId(const MachineFunction &MF); void emitPseudoProbe(const MachineInstr &MI); diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -93,6 +93,8 @@ enum { /// Whether this function is materializable. IsMaterializableBit = 0, + /// Whether this function is visible to regular objects with LTO, + IsVisibleToRegularObjBit, }; friend class SymbolTableListTraits; @@ -195,6 +197,15 @@ (V ? Mask : 0u)); } + bool isVisibleToRegularObj() const { + return getGlobalObjectSubClassData() & (1 << IsVisibleToRegularObjBit); + } + void setIsVisibleToRegularObj(bool V) { + unsigned Mask = 1 << IsVisibleToRegularObjBit; + setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | + (V ? Mask : 0u)); + } + /// getIntrinsicID - This method returns the ID number of the specified /// function, or Intrinsic::not_intrinsic if the function is not an /// intrinsic, or if the pointer is null. This value is always defined to be diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -342,6 +342,9 @@ /// summary). bool VisibleOutsideSummary = false; + /// This symbol is visible to regular objects. + bool VisibleToRegularObj = false; + /// The symbol was exported dynamically, and therefore could be referenced /// by a shared library not visible to the linker. bool ExportDynamic = false; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1386,7 +1386,31 @@ OutStreamer->popSection(); } +bool AsmPrinter::needsKCFITypeId(const MachineFunction &MF) { + const Function &F = MF.getFunction(); + const Module &M = *F.getParent(); + + if (!F.hasMetadata(LLVMContext::MD_kcfi_type)) + return false; + + // With LTO, we can drop type information from globals that are not + // address-taken, as long as they are not visible to regular objects. + if (!M.getModuleFlag("LTOPostLink") || F.isVisibleToRegularObj()) + return true; + + // Disable the optimization for ThinLTO as the address-taken property + // is not combined. + if (auto *MD = + mdconst::extract_or_null(M.getModuleFlag("ThinLTO"))) + if (MD->getZExtValue()) + return true; + + return F.hasAddressTaken(); +} + void AsmPrinter::emitKCFITypeId(const MachineFunction &MF) { + if (!needsKCFITypeId(MF)) + return; const Function &F = MF.getFunction(); if (const MDNode *MD = F.getMetadata(LLVMContext::MD_kcfi_type)) emitGlobalConstant(F.getParent()->getDataLayout(), diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -601,6 +601,7 @@ GlobalRes.VisibleOutsideSummary |= (Res.VisibleToRegularObj || Sym.isUsed() || !InSummary); + GlobalRes.VisibleToRegularObj |= Res.VisibleToRegularObj; GlobalRes.ExportDynamic |= Res.ExportDynamic; } } @@ -1164,6 +1165,9 @@ : GlobalValue::UnnamedAddr::None); if (EnableLTOInternalization && R.second.Partition == 0) GV->setLinkage(GlobalValue::InternalLinkage); + + if (auto *F = dyn_cast(GV)) + F->setIsVisibleToRegularObj(R.second.VisibleToRegularObj); } RegularLTO.CombinedModule->addModuleFlag(Module::Error, "LTOPostLink", 1); diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -156,8 +156,9 @@ return; ConstantInt *Type = nullptr; - if (const MDNode *MD = F.getMetadata(LLVMContext::MD_kcfi_type)) - Type = mdconst::extract(MD->getOperand(0)); + if (needsKCFITypeId(MF)) + if (const MDNode *MD = F.getMetadata(LLVMContext::MD_kcfi_type)) + Type = mdconst::extract(MD->getOperand(0)); // If we don't have a type to emit, just emit padding if needed to maintain // the same alignment for all functions. diff --git a/llvm/test/LTO/Resolution/X86/kcfi-seal.ll b/llvm/test/LTO/Resolution/X86/kcfi-seal.ll new file mode 100644 --- /dev/null +++ b/llvm/test/LTO/Resolution/X86/kcfi-seal.ll @@ -0,0 +1,33 @@ +; RUN: opt %s -o %t1.o +; RUN: llvm-lto2 run -O0 -o %t2.o %t1.o -r %t1.o,a,px -r %t1.o,b,p -r %t1.o,c,p -r %t1.o,p,p +; RUN: llvm-nm --numeric-sort %t2.o.0 | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +;; VisibleToRegularObj && !AddressTaken +; CHECK: T __cfi_a +; CHECK: T a +define void @a() !kcfi_type !1 { + ret void +} + +;; !VisibleToRegularObj && !AddressTaken +; CHECK-NOT: __cfi_b +; CHECK: t b +define void @b() !kcfi_type !1 { + ret void +} + +;; !VisibleToRegularObj && AddressTaken +; CHECK: t __cfi_c +; CHECK: t c +define void @c() !kcfi_type !1 { + ret void +} + +@p = global ptr @c + +!llvm.module.flags = !{!0} +!0 = !{i32 4, !"kcfi", i32 1} +!1 = !{i32 12345678}