Skip to content

Commit cc2ae13

Browse files
necipfazilPrabhuk
authored andcommitted
[clang][CallGraphSection] Add type id metadata to indirect call and targets
Create and add generalized type identifier metadata to indirect calls, and to functions that may be target to indirect calls. Type identifiers will be used by the back-end to construct the call graph section to precisely represent the possible targets for indirect calls. The type information is deliberately pulled from the front-end to have extra precision since some type information is lost at IR, and to ensure consistent type identifiers between object files compiled at different times (as C/C++ standards require language-level types to match). Original RFC: https://lists.llvm.org/pipermail/llvm-dev/2021-June/151044.html Updated RFC: https://lists.llvm.org/pipermail/llvm-dev/2021-July/151739.html Reviewed By: morehouse Differential Revision: https://reviews.llvm.org/D105909?id=358327 Pull Request: llvm#87573
1 parent 64c2d5f commit cc2ae13

File tree

16 files changed

+477
-17
lines changed

16 files changed

+477
-17
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5687,6 +5687,28 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
56875687
AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs);
56885688
Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs);
56895689

5690+
if (CGM.getCodeGenOpts().CallGraphSection) {
5691+
// FIXME: create operand bundle only for indirect calls, not for all
5692+
5693+
assert((TargetDecl && TargetDecl->getFunctionType() ||
5694+
Callee.getAbstractInfo().getCalleeFunctionProtoType()) &&
5695+
"cannot find callsite type");
5696+
5697+
QualType CST;
5698+
if (TargetDecl && TargetDecl->getFunctionType())
5699+
CST = QualType(TargetDecl->getFunctionType(), 0);
5700+
else if (const auto *FPT =
5701+
Callee.getAbstractInfo().getCalleeFunctionProtoType())
5702+
CST = QualType(FPT, 0);
5703+
5704+
if (!CST.isNull()) {
5705+
auto *TypeIdMD = CGM.CreateMetadataIdentifierGeneralized(CST);
5706+
auto *TypeIdMDVal =
5707+
llvm::MetadataAsValue::get(getLLVMContext(), TypeIdMD);
5708+
BundleList.emplace_back("type", TypeIdMDVal);
5709+
}
5710+
}
5711+
56905712
// Emit the actual call/invoke instruction.
56915713
llvm::CallBase *CI;
56925714
if (!InvokeDest) {

clang/lib/CodeGen/CGClass.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2247,7 +2247,14 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
22472247
const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
22482248
Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
22492249
CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type));
2250-
EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, false, Loc);
2250+
llvm::CallBase *CallOrInvoke = nullptr;
2251+
EmitCall(Info, Callee, ReturnValueSlot(), Args, &CallOrInvoke, false, Loc);
2252+
2253+
// Set type identifier metadata of indirect calls for call graph section.
2254+
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
2255+
CallOrInvoke->isIndirectCall())
2256+
CGM.CreateFunctionTypeMetadataForIcall(D->getType(), CallOrInvoke);
2257+
22512258

22522259
// Generate vtable assumptions if we're constructing a complete object
22532260
// with a vtable. We don't do this for base subobjects for two reasons:

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6003,6 +6003,11 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
60036003
}
60046004
}
60056005

6006+
// Set type identifier metadata of indirect calls for call graph section.
6007+
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
6008+
CallOrInvoke->isIndirectCall())
6009+
CGM.CreateFunctionTypeMetadataForIcall(QualType(FnType, 0), CallOrInvoke);
6010+
60066011
return Call;
60076012
}
60086013

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,17 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
9393
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
9494
auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(
9595
Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize);
96-
return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr,
96+
llvm::CallBase *CallOrInvoke = nullptr;
97+
auto Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke,
9798
CE && CE == MustTailCall,
9899
CE ? CE->getExprLoc() : SourceLocation());
100+
101+
// Set type identifier metadata of indirect calls for call graph section.
102+
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
103+
CallOrInvoke->isIndirectCall())
104+
CGM.CreateFunctionTypeMetadataForIcall(MD->getType(), CallOrInvoke);
105+
106+
return Call;
99107
}
100108

101109
RValue CodeGenFunction::EmitCXXDestructorCall(
@@ -119,9 +127,17 @@ RValue CodeGenFunction::EmitCXXDestructorCall(
119127
CallArgList Args;
120128
commonEmitCXXMemberOrOperatorCall(*this, Dtor, This, ImplicitParam,
121129
ImplicitParamTy, CE, Args, nullptr);
122-
return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
123-
ReturnValueSlot(), Args, nullptr, CE && CE == MustTailCall,
130+
llvm::CallBase *CallOrInvoke = nullptr;
131+
auto Call = EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
132+
ReturnValueSlot(), Args, &CallOrInvoke, CE && CE == MustTailCall,
124133
CE ? CE->getExprLoc() : SourceLocation{});
134+
135+
// Set type identifier metadata of indirect calls for call graph section.
136+
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
137+
CallOrInvoke->isIndirectCall())
138+
CGM.CreateFunctionTypeMetadataForIcall(DtorDecl->getType(), CallOrInvoke);
139+
140+
return Call;
125141
}
126142

127143
RValue CodeGenFunction::EmitCXXPseudoDestructorExpr(
@@ -482,10 +498,18 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
482498

483499
// And the rest of the call args
484500
EmitCallArgs(Args, FPT, E->arguments());
485-
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
501+
llvm::CallBase *CallOrInvoke = nullptr;
502+
auto Call = EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
486503
/*PrefixSize=*/0),
487-
Callee, ReturnValue, Args, nullptr, E == MustTailCall,
504+
Callee, ReturnValue, Args, &CallOrInvoke, E == MustTailCall,
488505
E->getExprLoc());
506+
507+
// Set type identifier metadata of indirect calls for call graph section.
508+
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
509+
CallOrInvoke->isIndirectCall())
510+
CGM.CreateFunctionTypeMetadataForIcall(QualType(FPT, 0), CallOrInvoke);
511+
512+
return Call;
489513
}
490514

491515
RValue

clang/lib/CodeGen/CGObjCMac.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,6 +2220,14 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
22202220
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
22212221
&CallSite);
22222222

2223+
// Set type identifier metadata of indirect calls for call graph section.
2224+
if (CGM.getCodeGenOpts().CallGraphSection && Method && CallSite &&
2225+
CallSite->isIndirectCall()) {
2226+
if (const auto *FnType = Method->getFunctionType()) {
2227+
CGM.CreateFunctionTypeMetadataForIcall(QualType(FnType, 0), CallSite);
2228+
}
2229+
}
2230+
22232231
// Mark the call as noreturn if the method is marked noreturn and the
22242232
// receiver cannot be null.
22252233
if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,8 +2494,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
24942494

24952495
// In the cross-dso CFI mode with canonical jump tables, we want !type
24962496
// attributes on definitions only.
2497-
if (CodeGenOpts.SanitizeCfiCrossDso &&
2498-
CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
2497+
if ((CodeGenOpts.SanitizeCfiCrossDso &&
2498+
CodeGenOpts.SanitizeCfiCanonicalJumpTables) || CodeGenOpts.CallGraphSection) {
24992499
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
25002500
// Skip available_externally functions. They won't be codegen'ed in the
25012501
// current module anyway.
@@ -2685,7 +2685,17 @@ static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) {
26852685

26862686
void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
26872687
llvm::Function *F) {
2688-
// Only if we are checking indirect calls.
2688+
bool EmittedMDIdGeneralized = false;
2689+
if (CodeGenOpts.CallGraphSection &&
2690+
(!F->hasLocalLinkage() ||
2691+
F->getFunction().hasAddressTaken(nullptr, /* IgnoreCallbackUses */ true,
2692+
/* IgnoreAssumeLikeCalls */ true,
2693+
/* IgnoreLLVMUsed */ false))) {
2694+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
2695+
EmittedMDIdGeneralized = true;
2696+
}
2697+
2698+
// Add additional metadata only if we are checking indirect calls with CFI.
26892699
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
26902700
return;
26912701

@@ -2696,14 +2706,27 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
26962706

26972707
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
26982708
F->addTypeMetadata(0, MD);
2699-
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
2709+
// Add the generalized identifier if not added already.
2710+
if (!EmittedMDIdGeneralized)
2711+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
27002712

27012713
// Emit a hash-based bit set entry for cross-DSO calls.
27022714
if (CodeGenOpts.SanitizeCfiCrossDso)
27032715
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
27042716
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
27052717
}
27062718

2719+
void CodeGenModule::CreateFunctionTypeMetadataForIcall(const QualType &QT,
2720+
llvm::CallBase *CB) {
2721+
// Only if needed for call graph section and only for indirect calls.
2722+
if (!(CodeGenOpts.CallGraphSection && CB && CB->isIndirectCall()))
2723+
return;
2724+
2725+
auto *MD = CreateMetadataIdentifierGeneralized(QT);
2726+
auto *MDN = llvm::MDNode::get(getLLVMContext(), MD);
2727+
CB->setMetadata(llvm::LLVMContext::MD_type, MDN);
2728+
}
2729+
27072730
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
27082731
llvm::LLVMContext &Ctx = F->getContext();
27092732
llvm::MDBuilder MDB(Ctx);
@@ -2831,7 +2854,8 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
28312854
// are non-canonical then we need type metadata in order to produce the local
28322855
// jump table.
28332856
if (!CodeGenOpts.SanitizeCfiCrossDso ||
2834-
!CodeGenOpts.SanitizeCfiCanonicalJumpTables)
2857+
!CodeGenOpts.SanitizeCfiCanonicalJumpTables ||
2858+
CodeGenOpts.CallGraphSection)
28352859
CreateFunctionTypeMetadataForIcall(FD, F);
28362860

28372861
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,10 @@ class CodeGenModule : public CodeGenTypeCache {
14731473
void CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
14741474
llvm::Function *F);
14751475

1476+
/// Create and attach type metadata to the given call.
1477+
void CreateFunctionTypeMetadataForIcall(const QualType &QT,
1478+
llvm::CallBase *CB);
1479+
14761480
/// Set type metadata to the given function.
14771481
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
14781482

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Tests that we assign appropriate identifiers to indirect calls and targets
2+
// specifically for C++ class and instance methods.
3+
4+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \
5+
// RUN: -emit-llvm -o %t %s
6+
// RUN: FileCheck --check-prefix=FT %s < %t
7+
// RUN: FileCheck --check-prefix=CST %s < %t
8+
9+
////////////////////////////////////////////////////////////////////////////////
10+
// Class definitions (check for indirect target metadata)
11+
12+
class Cls1 {
13+
public:
14+
// FT-DAG: define {{.*}} ptr @_ZN4Cls18receiverEPcPf({{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]]
15+
static int *receiver(char *a, float *b) { return 0; }
16+
};
17+
18+
class Cls2 {
19+
public:
20+
int *(*fp)(char *, float *);
21+
22+
// FT-DAG: define {{.*}} i32 @_ZN4Cls22f1Ecfd({{.*}} !type [[F_TCLS2F1:![0-9]+]]
23+
int f1(char a, float b, double c) { return 0; }
24+
25+
// FT-DAG: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd({{.*}} !type [[F_TCLS2F2:![0-9]+]]
26+
int *f2(char *a, float *b, double *c) { return 0; }
27+
28+
// FT-DAG: define {{.*}} void @_ZN4Cls22f3E4Cls1({{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
29+
void f3(Cls1 a) {}
30+
31+
// FT-DAG: define {{.*}} void @_ZN4Cls22f4E4Cls1({{.*}} !type [[F_TCLS2F3F4]]
32+
void f4(const Cls1 a) {}
33+
34+
// FT-DAG: define {{.*}} void @_ZN4Cls22f5EP4Cls1({{.*}} !type [[F_TCLS2F5:![0-9]+]]
35+
void f5(Cls1 *a) {}
36+
37+
// FT-DAG: define {{.*}} void @_ZN4Cls22f6EPK4Cls1({{.*}} !type [[F_TCLS2F6:![0-9]+]]
38+
void f6(const Cls1 *a) {}
39+
40+
// FT-DAG: define {{.*}} void @_ZN4Cls22f7ER4Cls1({{.*}} !type [[F_TCLS2F7:![0-9]+]]
41+
void f7(Cls1 &a) {}
42+
43+
// FT-DAG: define {{.*}} void @_ZN4Cls22f8ERK4Cls1({{.*}} !type [[F_TCLS2F8:![0-9]+]]
44+
void f8(const Cls1 &a) {}
45+
46+
// FT-DAG: define {{.*}} void @_ZNK4Cls22f9Ev({{.*}} !type [[F_TCLS2F9:![0-9]+]]
47+
void f9() const {}
48+
};
49+
50+
// FT-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPvS_S_E.generalized"}
51+
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPvS_S_S_E.generalized"}
52+
// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
53+
// FT-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
54+
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvPvE.generalized"}
55+
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
56+
// FT-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
57+
// FT-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
58+
// FT-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
59+
60+
////////////////////////////////////////////////////////////////////////////////
61+
// Callsites (check for indirect callsite operand bundles)
62+
63+
// CST-LABEL: define {{.*}} @_Z3foov
64+
void foo() {
65+
Cls2 ObjCls2;
66+
ObjCls2.fp = &Cls1::receiver;
67+
68+
// CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPvS_S_E.generalized") ]
69+
ObjCls2.fp(0, 0);
70+
71+
auto fp_f1 = &Cls2::f1;
72+
auto fp_f2 = &Cls2::f2;
73+
auto fp_f3 = &Cls2::f3;
74+
auto fp_f4 = &Cls2::f4;
75+
auto fp_f5 = &Cls2::f5;
76+
auto fp_f6 = &Cls2::f6;
77+
auto fp_f7 = &Cls2::f7;
78+
auto fp_f8 = &Cls2::f8;
79+
auto fp_f9 = &Cls2::f9;
80+
81+
Cls2 *ObjCls2Ptr = &ObjCls2;
82+
Cls1 Cls1Param;
83+
84+
// CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFicfdE.generalized") ]
85+
(ObjCls2Ptr->*fp_f1)(0, 0, 0);
86+
87+
// CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPvS_S_S_E.generalized") ]
88+
(ObjCls2Ptr->*fp_f2)(0, 0, 0);
89+
90+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ]
91+
(ObjCls2Ptr->*fp_f3)(Cls1Param);
92+
93+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ]
94+
(ObjCls2Ptr->*fp_f4)(Cls1Param);
95+
96+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPvE.generalized") ]
97+
(ObjCls2Ptr->*fp_f5)(&Cls1Param);
98+
99+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPKvE.generalized") ]
100+
(ObjCls2Ptr->*fp_f6)(&Cls1Param);
101+
102+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvR4Cls1E.generalized") ]
103+
(ObjCls2Ptr->*fp_f7)(Cls1Param);
104+
105+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvRK4Cls1E.generalized") ]
106+
(ObjCls2Ptr->*fp_f8)(Cls1Param);
107+
108+
// CST: call void %{{.*}} [ "type"(metadata !"_ZTSKFvvE.generalized") ]
109+
(ObjCls2Ptr->*fp_f9)();
110+
}

0 commit comments

Comments
 (0)