Skip to content

Commit d9edca4

Browse files
authored
[CodeGen] Ensure relative vtables use llvm.type.checked.load.relative (#126785)
This intrinsic is used when whole program vtables is used in conjunction with either CFI or virtual function elimination. The `llvm.type.checked.load` is unconditionally used, but we need to use the relative intrinsic for WPD and CFI to work correctly.
1 parent b8337bc commit d9edca4

File tree

5 files changed

+33
-20
lines changed

5 files changed

+33
-20
lines changed

clang/lib/CodeGen/CGClass.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2937,9 +2937,13 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
29372937
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
29382938
llvm::Value *TypeId = llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
29392939

2940+
auto CheckedLoadIntrinsic = CGM.getVTables().useRelativeLayout()
2941+
? llvm::Intrinsic::type_checked_load_relative
2942+
: llvm::Intrinsic::type_checked_load;
29402943
llvm::Value *CheckedLoad = Builder.CreateCall(
2941-
CGM.getIntrinsic(llvm::Intrinsic::type_checked_load),
2944+
CGM.getIntrinsic(CheckedLoadIntrinsic),
29422945
{VTable, llvm::ConstantInt::get(Int32Ty, VTableByteOffset), TypeId});
2946+
29432947
llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
29442948

29452949
std::string TypeName = RD->getQualifiedNameAsString();

clang/lib/CodeGen/CGVTables.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@ class CodeGenVTables {
7575
bool vtableHasLocalLinkage,
7676
bool isCompleteDtor) const;
7777

78-
bool useRelativeLayout() const;
79-
80-
llvm::Type *getVTableComponentType() const;
81-
8278
public:
8379
/// Add vtable components for the given vtable layout to the given
8480
/// global initializer.
@@ -151,6 +147,12 @@ class CodeGenVTables {
151147

152148
/// Specify a global should not be instrumented with hwasan.
153149
void RemoveHwasanMetadata(llvm::GlobalValue *GV) const;
150+
151+
/// Return the type used as components for a vtable.
152+
llvm::Type *getVTableComponentType() const;
153+
154+
/// Return true if the relative vtable layout is used.
155+
bool useRelativeLayout() const;
154156
};
155157

156158
} // end namespace CodeGen

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,20 +2189,22 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
21892189
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
21902190
llvm::Value *VFunc, *VTableSlotPtr = nullptr;
21912191
auto &Schema = CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers;
2192+
2193+
llvm::Type *ComponentTy = CGM.getVTables().getVTableComponentType();
2194+
uint64_t ByteOffset =
2195+
VTableIndex * CGM.getDataLayout().getTypeSizeInBits(ComponentTy) / 8;
2196+
21922197
if (!Schema && CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) {
2193-
VFunc = CGF.EmitVTableTypeCheckedLoad(
2194-
MethodDecl->getParent(), VTable, PtrTy,
2195-
VTableIndex *
2196-
CGM.getContext().getTargetInfo().getPointerWidth(LangAS::Default) /
2197-
8);
2198+
VFunc = CGF.EmitVTableTypeCheckedLoad(MethodDecl->getParent(), VTable,
2199+
PtrTy, ByteOffset);
21982200
} else {
21992201
CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
22002202

22012203
llvm::Value *VFuncLoad;
22022204
if (CGM.getItaniumVTableContext().isRelativeLayout()) {
22032205
VFuncLoad = CGF.Builder.CreateCall(
22042206
CGM.getIntrinsic(llvm::Intrinsic::load_relative, {CGM.Int32Ty}),
2205-
{VTable, llvm::ConstantInt::get(CGM.Int32Ty, 4 * VTableIndex)});
2207+
{VTable, llvm::ConstantInt::get(CGM.Int32Ty, ByteOffset)});
22062208
} else {
22072209
VTableSlotPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
22082210
PtrTy, VTable, VTableIndex, "vfn");

clang/test/CodeGen/fat-lto-objects-cfi.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ void foo(const void* ptr, size_t len, long disp_addr,
7070
// COM: llvm.type.checked.load, so we need to match the function body first.
7171
// NO_CHECKED_LOAD-LABEL: entry:
7272
// NO_CHECKED_LOAD-NEXT: %vtable = load ptr, ptr %p1
73-
// NO_CHECKED_LOAD-NOT: llvm.type.checked.load
74-
// NO_CHECKED_LOAD-NEXT: %vfunc = load ptr, ptr %vtable
75-
// NO_CHECKED_LOAD-NEXT: %call = tail call {{.*}} %vfunc(ptr {{.*}} %p1)
73+
// NO_CHECKED_LOAD-NOT: llvm.type.checked.load.relative
74+
// NO_CHECKED_LOAD-NEXT: %rel_load = tail call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
75+
// NO_CHECKED_LOAD-NEXT: %call = tail call {{.*}} %rel_load(ptr {{.*}} %p1)
7676
// NO_CHECKED_LOAD-NEXT: ret void
7777

7878
// COM: Ensure that we don't crash in the backend anymore when clang uses

clang/test/CodeGenCXX/type-metadata.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
// RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -O2 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM-OPT --check-prefix=RV-OPT-LAYOUT %s
3131

3232
// Tests for cfi + whole-program-vtables:
33-
// RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM-HIDDEN --check-prefix=ITANIUM-COMMON-MD --check-prefix=RV-MD --check-prefix=TC-ITANIUM %s
33+
// RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM-HIDDEN --check-prefix=ITANIUM-COMMON-MD --check-prefix=RV-MD --check-prefix=TC-ITANIUM-RV %s
3434

3535
// Tests that type metadata are annotated on vtables with `-profile-instrument=llvm` (which is equivalent to clang driver option `-fprofile-generate` without `-fcs-profile-generate`):
3636
// - In clang driver, `-fprofile-instrument` cc1 option is set to 'llvm' iff clang driver option `-fprofile-generate{,=}` is taking effect.
@@ -178,7 +178,8 @@ void af(A *a) {
178178
// TT-ITANIUM-HIDDEN: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
179179
// TT-ITANIUM-DEFAULT: [[P:%[^ ]*]] = call i1 @llvm.public.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
180180
// TT-MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata !"?AUA@@")
181-
// TC-ITANIUM: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
181+
// TC-ITANIUM: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
182+
// TC-ITANIUM-RV: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
182183
// TC-MS: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
183184
// CFI-VT: [[P:%[^ ]*]] = extractvalue { ptr, i1 } [[PAIR]], 1
184185
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT]], metadata !"all-vtables")
@@ -211,7 +212,8 @@ void df1(D *d) {
211212
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
212213
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
213214
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUA@@")
214-
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
215+
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
216+
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
215217
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
216218
d->f();
217219
}
@@ -222,7 +224,8 @@ void dg1(D *d) {
222224
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
223225
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
224226
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUB@@")
225-
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
227+
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
228+
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 4, metadata !"_ZTS1B")
226229
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUB@@")
227230
d->g();
228231
}
@@ -233,7 +236,8 @@ void dh1(D *d) {
233236
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
234237
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
235238
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
236-
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
239+
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
240+
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 8, metadata ![[DTYPE]])
237241
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata ![[DTYPE:[0-9]+]])
238242
d->h();
239243
}
@@ -293,7 +297,8 @@ void f(D *d) {
293297
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
294298
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
295299
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUA@test2@@")
296-
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
300+
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
301+
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 4, metadata !"_ZTSN5test21DE")
297302
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@test2@@")
298303
d->m_fn1();
299304
}

0 commit comments

Comments
 (0)