[BOLT] Make safe ICF work with relative vtable (#170629)
To support relative vtable, we divide each vtable entry address by 4 instead of 8 when tracking addresses covered by vtable using bitvector. This guarantees accuracy, saves the trouble of checking for each vtable whether it is relative, and is also necessary for libraries for which some contributing compilation units are compiled with relative vtable while others are not.
This commit is contained in:
parent
09b0885569
commit
4c17f9b684
3 changed files with 32 additions and 3 deletions
|
|
@ -37,17 +37,19 @@ public:
|
|||
Error runOnFunctions(BinaryContext &BC) override;
|
||||
|
||||
private:
|
||||
static constexpr uint64_t VTableAddressGranularity = 4;
|
||||
|
||||
/// Bit vector of memory addresses of vtables.
|
||||
llvm::SparseBitVector<> VTableBitVector;
|
||||
|
||||
/// Return true if the memory address is in a vtable.
|
||||
bool isAddressInVTable(uint64_t Address) const {
|
||||
return VTableBitVector.test(Address / 8);
|
||||
return VTableBitVector.test(Address / VTableAddressGranularity);
|
||||
}
|
||||
|
||||
/// Mark memory address of a vtable as used.
|
||||
void setAddressUsedInVTable(uint64_t Address) {
|
||||
VTableBitVector.set(Address / 8);
|
||||
VTableBitVector.set(Address / VTableAddressGranularity);
|
||||
}
|
||||
|
||||
/// Scan symbol table and mark memory addresses of
|
||||
|
|
|
|||
|
|
@ -380,7 +380,8 @@ void IdenticalCodeFolding::initVTableReferences(const BinaryContext &BC) {
|
|||
if (!Data->getName().starts_with("_ZTV") && // vtable
|
||||
!Data->getName().starts_with("_ZTCN")) // construction vtable
|
||||
continue;
|
||||
for (uint64_t I = Address, End = I + Data->getSize(); I < End; I += 8)
|
||||
for (uint64_t I = Address, End = I + Data->getSize(); I < End;
|
||||
I += VTableAddressGranularity)
|
||||
setAddressUsedInVTable(I);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
bolt/test/safe-icf-relative-vtable.cpp
Normal file
26
bolt/test/safe-icf-relative-vtable.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Test safe ICF works with binaries that contain relative vtable.
|
||||
|
||||
// REQUIRES: system-linux,asserts
|
||||
|
||||
// RUN: %clang %cxxflags -o %t.so %s -Wl,-q -fno-rtti
|
||||
// RUN: llvm-bolt %t.so -o %t.bolt --no-threads --icf=safe \
|
||||
// RUN: --debug-only=bolt-icf 2>&1 | FileCheck %s
|
||||
|
||||
// RUN: %clang %cxxflags -o %t.so %s -Wl,-q -fno-rtti \
|
||||
// RUN: -fexperimental-relative-c++-abi-vtables
|
||||
// RUN: llvm-bolt %t.so -o %t.bolt --no-threads --icf=safe \
|
||||
// RUN: --debug-only=bolt-icf 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: folding {{.*bar.*}} into {{.*foo.*}}
|
||||
// CHECK-NOT: skipping function with reference taken {{.*bar.*}}
|
||||
|
||||
class TT {
|
||||
public:
|
||||
virtual int foo(int a) { return ++a; }
|
||||
virtual int bar(int a) { return ++a; }
|
||||
};
|
||||
|
||||
int main() {
|
||||
TT T;
|
||||
return T.foo(0) + T.bar(1);
|
||||
}
|
||||
Loading…
Reference in a new issue