diff --git a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h --- a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h +++ b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h @@ -42,6 +42,10 @@ void appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *Data = nullptr); +/// Sets the KCFI type for the function. Used for compiler-generated functions +/// that are indirectly called in instrumented code. +void setKCFIType(Module &M, Function &F, StringRef MangledType); + FunctionCallee declareSanitizerInitFunction(Module &M, StringRef InitName, ArrayRef InitArgTypes); diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp --- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -119,7 +119,8 @@ function_ref GetBPI, function_ref GetTLI); - Function *createInternalFunction(FunctionType *FTy, StringRef Name); + Function *createInternalFunction(FunctionType *FTy, StringRef Name, + StringRef MangledType = ""); void emitGlobalConstructor( SmallVectorImpl> &CountersBySP); @@ -976,13 +977,16 @@ } Function *GCOVProfiler::createInternalFunction(FunctionType *FTy, - StringRef Name) { + StringRef Name, + StringRef MangledType /*=""*/) { Function *F = Function::createWithDefaultAttr( FTy, GlobalValue::InternalLinkage, 0, Name, M); F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); F->addFnAttr(Attribute::NoUnwind); if (Options.NoRedZone) F->addFnAttr(Attribute::NoRedZone); + if (!MangledType.empty()) + setKCFIType(*M, *F, MangledType); return F; } @@ -995,7 +999,7 @@ // be executed at exit and the "__llvm_gcov_reset" function to be executed // when "__gcov_flush" is called. FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Function *F = createInternalFunction(FTy, "__llvm_gcov_init"); + Function *F = createInternalFunction(FTy, "__llvm_gcov_init", "_ZTSFvvE"); F->addFnAttr(Attribute::NoInline); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); @@ -1071,7 +1075,8 @@ FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); if (!WriteoutF) - WriteoutF = createInternalFunction(WriteoutFTy, "__llvm_gcov_writeout"); + WriteoutF = + createInternalFunction(WriteoutFTy, "__llvm_gcov_writeout", "_ZTSFvvE"); WriteoutF->addFnAttr(Attribute::NoInline); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); @@ -1317,7 +1322,7 @@ FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *ResetF = M->getFunction("__llvm_gcov_reset"); if (!ResetF) - ResetF = createInternalFunction(FTy, "__llvm_gcov_reset"); + ResetF = createInternalFunction(FTy, "__llvm_gcov_reset", "_ZTSFvvE"); ResetF->addFnAttr(Attribute::NoInline); BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", ResetF); diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -150,7 +150,7 @@ removeFromUsedList(M, "llvm.compiler.used", ShouldRemove); } -static void setKCFIType(Module &M, Function &F, StringRef MangledType) { +void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) { if (!M.getModuleFlag("kcfi")) return; // Matches CodeGenModule::CreateKCFITypeId in Clang. diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi.ll b/llvm/test/Transforms/GCOVProfiling/kcfi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/GCOVProfiling/kcfi.ll @@ -0,0 +1,31 @@ +;; Ensure __llvm_gcov_(writeout|reset|init) have !kcfi_type with KCFI. +; RUN: mkdir -p %t && cd %t +; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +define dso_local void @empty() !dbg !5 { +entry: + ret void, !dbg !8 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "a.c", directory: "") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = distinct !DISubprogram(name: "empty", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!6 = !DISubroutineType(types: !7) +!7 = !{null} +!8 = !DILocation(line: 2, column: 1, scope: !5) +!9 = !{i32 4, !"kcfi", i32 1} + +; CHECK: define internal void @__llvm_gcov_writeout() +; CHECK-SAME: !kcfi_type +; CHECK: define internal void @__llvm_gcov_reset() +; CHECK-SAME: !kcfi_type +; CHECK: define internal void @__llvm_gcov_init() +; CHECK-SAME: !kcfi_type