Index: clang/lib/CodeGen/CGClass.cpp =================================================================== --- clang/lib/CodeGen/CGClass.cpp +++ clang/lib/CodeGen/CGClass.cpp @@ -2182,7 +2182,13 @@ const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall( Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs); CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type)); - EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, false, Loc); + llvm::CallBase *CallOrInvoke = nullptr; + EmitCall(Info, Callee, ReturnValueSlot(), Args, &CallOrInvoke, false, Loc); + + // Set type identifier metadata of indirect calls for call graph section. + if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke && + CallOrInvoke->isIndirectCall()) + CGM.CreateFunctionTypeMetadataForIcall(D->getType(), CallOrInvoke); // Generate vtable assumptions if we're constructing a complete object // with a vtable. We don't do this for base subobjects for two reasons: Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -5311,6 +5311,11 @@ CalleeDecl); } + // Set type identifier metadata of indirect calls for call graph section. + if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke && + CallOrInvoke->isIndirectCall()) + CGM.CreateFunctionTypeMetadataForIcall(QualType(FnType, 0), CallOrInvoke); + return Call; } Index: clang/lib/CodeGen/CGExprCXX.cpp =================================================================== --- clang/lib/CodeGen/CGExprCXX.cpp +++ clang/lib/CodeGen/CGExprCXX.cpp @@ -86,9 +86,17 @@ *this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs); auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall( Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize); - return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr, - CE && CE == MustTailCall, - CE ? CE->getExprLoc() : SourceLocation()); + llvm::CallBase *CallOrInvoke = nullptr; + auto Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke, + CE && CE == MustTailCall, + CE ? CE->getExprLoc() : SourceLocation()); + + // Set type identifier metadata of indirect calls for call graph section. + if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke && + CallOrInvoke->isIndirectCall()) + CGM.CreateFunctionTypeMetadataForIcall(MD->getType(), CallOrInvoke); + + return Call; } RValue CodeGenFunction::EmitCXXDestructorCall( @@ -112,9 +120,18 @@ CallArgList Args; commonEmitCXXMemberOrOperatorCall(*this, DtorDecl, This, ImplicitParam, ImplicitParamTy, CE, Args, nullptr); - return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee, - ReturnValueSlot(), Args, nullptr, CE && CE == MustTailCall, - CE ? CE->getExprLoc() : SourceLocation{}); + llvm::CallBase *CallOrInvoke = nullptr; + auto Call = + EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee, + ReturnValueSlot(), Args, &CallOrInvoke, CE && CE == MustTailCall, + CE ? CE->getExprLoc() : SourceLocation{}); + + // Set type identifier metadata of indirect calls for call graph section. + if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke && + CallOrInvoke->isIndirectCall()) + CGM.CreateFunctionTypeMetadataForIcall(DtorDecl->getType(), CallOrInvoke); + + return Call; } RValue CodeGenFunction::EmitCXXPseudoDestructorExpr( @@ -471,10 +488,18 @@ // And the rest of the call args EmitCallArgs(Args, FPT, E->arguments()); - return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required, - /*PrefixSize=*/0), - Callee, ReturnValue, Args, nullptr, E == MustTailCall, - E->getExprLoc()); + llvm::CallBase *CallOrInvoke = nullptr; + auto Call = EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required, + /*PrefixSize=*/0), + Callee, ReturnValue, Args, &CallOrInvoke, + E == MustTailCall, E->getExprLoc()); + + // Set type identifier metadata of indirect calls for call graph section. + if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke && + CallOrInvoke->isIndirectCall()) + CGM.CreateFunctionTypeMetadataForIcall(QualType(FPT, 0), CallOrInvoke); + + return Call; } RValue Index: clang/lib/CodeGen/CGObjCMac.cpp =================================================================== --- clang/lib/CodeGen/CGObjCMac.cpp +++ clang/lib/CodeGen/CGObjCMac.cpp @@ -2279,6 +2279,13 @@ CGCallee Callee = CGCallee::forDirect(BitcastFn); RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs, &CallSite); + // Set type identifier metadata of indirect calls for call graph section. + if (CGM.getCodeGenOpts().CallGraphSection && Method && CallSite && + CallSite->isIndirectCall()) { + if (const auto *FnType = Method->getFunctionType()) { + CGM.CreateFunctionTypeMetadataForIcall(QualType(FnType, 0), CallSite); + } + } // Mark the call as noreturn if the method is marked noreturn and the // receiver cannot be null. Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1406,6 +1406,10 @@ void CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD, llvm::Function *F); + /// Create and attach type metadata to the given call. + void CreateFunctionTypeMetadataForIcall(const QualType &QT, + llvm::CallBase *CB); + /// Whether this function's return type has no side effects, and thus may /// be trivially discarded if it is unused. bool MayDropFunctionReturn(const ASTContext &Context, QualType ReturnType); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -1873,8 +1873,9 @@ // In the cross-dso CFI mode with canonical jump tables, we want !type // attributes on definitions only. - if (CodeGenOpts.SanitizeCfiCrossDso && - CodeGenOpts.SanitizeCfiCanonicalJumpTables) { + if ((CodeGenOpts.SanitizeCfiCrossDso && + CodeGenOpts.SanitizeCfiCanonicalJumpTables) || + CodeGenOpts.CallGraphSection) { if (auto *FD = dyn_cast(D)) { // Skip available_externally functions. They won't be codegen'ed in the // current module anyway. @@ -2057,7 +2058,17 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD, llvm::Function *F) { - // Only if we are checking indirect calls. + bool EmittedMDIdGeneralized = false; + if (CodeGenOpts.CallGraphSection && + (!F->hasLocalLinkage() || + F->getFunction().hasAddressTaken(nullptr, /* IgnoreCallbackUses */ true, + /* IgnoreAssumeLikeCalls */ true, + /* IgnoreLLVMUsed */ false))) { + F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType())); + EmittedMDIdGeneralized = true; + } + + // Add additional metadata only if we are checking indirect calls with CFI. if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall)) return; @@ -2068,7 +2079,9 @@ llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType()); F->addTypeMetadata(0, MD); - F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType())); + // Add the generalized identifier if not added already. + if (!EmittedMDIdGeneralized) + F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType())); // Emit a hash-based bit set entry for cross-DSO calls. if (CodeGenOpts.SanitizeCfiCrossDso) @@ -2076,6 +2089,17 @@ F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId)); } +void CodeGenModule::CreateFunctionTypeMetadataForIcall(const QualType &QT, + llvm::CallBase *CB) { + // Only if needed for call graph section and only for indirect calls. + if (!(CodeGenOpts.CallGraphSection && CB && CB->isIndirectCall())) + return; + + auto *MD = CreateMetadataIdentifierGeneralized(QT); + auto *MDN = llvm::MDNode::get(getLLVMContext(), MD); + CB->setMetadata(llvm::LLVMContext::MD_type, MDN); +} + void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction, bool IsThunk) { @@ -2150,7 +2174,8 @@ // are non-canonical then we need type metadata in order to produce the local // jump table. if (!CodeGenOpts.SanitizeCfiCrossDso || - !CodeGenOpts.SanitizeCfiCanonicalJumpTables) + !CodeGenOpts.SanitizeCfiCanonicalJumpTables || + CodeGenOpts.CallGraphSection) CreateFunctionTypeMetadataForIcall(FD, F); if (getLangOpts().OpenMP && FD->hasAttr()) Index: clang/test/CodeGen/call-graph-section.c =================================================================== --- /dev/null +++ clang/test/CodeGen/call-graph-section.c @@ -0,0 +1,47 @@ +// Tests that we assign appropriate identifiers to indirect calls and targets. + +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s + +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fcall-graph-section -S \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s + +// CHECK: define {{(dso_local )?}}void @foo({{.*}} !type [[TVOID_GENERALIZED:![0-9]+]] +void foo() { +} + +// CHECK: define {{(dso_local )?}}void @bar({{.*}} !type [[TVOID_GENERALIZED:![0-9]+]] +void bar() { + void (*fp)() = foo; + // CHECK: call {{.*}} !type [[TVOID_GENERALIZED:![0-9]+]] + return fp(); +} + +// CHECK: define {{(dso_local )?}}i32 @baz({{.*}} !type [[TPRIMITIVE_GENERALIZED:![0-9]+]] +int baz(char a, float b, double c) { + return 1; +} + +// CHECK: define {{(dso_local )?}}i32* @qux({{.*}} !type [[TPTR_GENERALIZED:![0-9]+]] +int *qux(char *a, float *b, double *c) { + return 0; +} + +// CHECK: define {{(dso_local )?}}void @corge({{.*}} !type [[TVOID_GENERALIZED:![0-9]+]] +void corge() { + int (*fp_baz)(char, float, double) = baz; + // CHECK: call i32 {{.*}}, !type [[TPRIMITIVE_GENERALIZED:![0-9]+]] + fp_baz('a', .0f, .0); + + int *(*fp_qux)(char *, float *, double *) = qux; + // CHECK: call i32* {{.*}}, !type [[TPTR_GENERALIZED:![0-9]+]] + fp_qux(0, 0, 0); +} + +// ITANIUM-DAG: [[TVOID_GENERALIZED]] = !{{{.*}}!"_ZTSFvE.generalized"} +// ITANIUM-DAG: [[TPRIMITIVE_GENERALIZED]] = !{{{.*}}!"_ZTSFicfdE.generalized"} +// ITANIUM-DAG: [[TPTR_GENERALIZED]] = !{{{.*}}!"_ZTSFPvS_S_S_E.generalized"} +// MS-DAG: [[TVOID_GENERALIZED]] = !{{{.*}}!"?6AX@Z.generalized"} +// MS-DAG: [[TPRIMITIVE_GENERALIZED]] = !{{{.*}}!"?6AHDMN@Z.generalized"} +// MS-DAG: [[TPTR_GENERALIZED]] = !{{{.*}}!"?6APEAXPEAX00@Z.generalized"} +