Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bolt/lib/Core/Relocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static bool isSupportedAArch64(uint32_t Type) {
case ELF::R_AARCH64_MOVW_UABS_G2:
case ELF::R_AARCH64_MOVW_UABS_G2_NC:
case ELF::R_AARCH64_MOVW_UABS_G3:
case ELF::R_AARCH64_PLT32:
return true;
}
}
Expand Down Expand Up @@ -202,6 +203,7 @@ static size_t getSizeForTypeAArch64(uint32_t Type) {
case ELF::R_AARCH64_MOVW_UABS_G2_NC:
case ELF::R_AARCH64_MOVW_UABS_G3:
case ELF::R_AARCH64_ABS32:
case ELF::R_AARCH64_PLT32:
return 4;
case ELF::R_AARCH64_ABS64:
case ELF::R_AARCH64_PREL64:
Expand Down Expand Up @@ -354,6 +356,7 @@ static uint64_t extractValueAArch64(uint32_t Type, uint64_t Contents,
case ELF::R_AARCH64_PREL16:
return static_cast<int64_t>(PC) + SignExtend64<16>(Contents & 0xffff);
case ELF::R_AARCH64_PREL32:
case ELF::R_AARCH64_PLT32:
return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
case ELF::R_AARCH64_PREL64:
return static_cast<int64_t>(PC) + Contents;
Expand Down Expand Up @@ -676,6 +679,7 @@ static bool isPCRelativeAArch64(uint32_t Type) {
case ELF::R_AARCH64_PREL16:
case ELF::R_AARCH64_PREL32:
case ELF::R_AARCH64_PREL64:
case ELF::R_AARCH64_PLT32:
return true;
}
}
Expand Down
32 changes: 29 additions & 3 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2603,7 +2603,9 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
const RelocationRef &Rel) {
const bool IsAArch64 = BC->isAArch64();
const bool IsX86 = BC->isX86();
const bool IsFromCode = RelocatedSection.isText();
const bool IsWritable = BinarySection(*BC, RelocatedSection).isWritable();

SmallString<16> TypeName;
Rel.getTypeName(TypeName);
Expand All @@ -2612,15 +2614,15 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
return;

// Adjust the relocation type as the linker might have skewed it.
if (BC->isX86() && (RType & ELF::R_X86_64_converted_reloc_bit)) {
if (IsX86 && (RType & ELF::R_X86_64_converted_reloc_bit)) {
if (opts::Verbosity >= 1)
dbgs() << "BOLT-WARNING: ignoring R_X86_64_converted_reloc_bit\n";
RType &= ~ELF::R_X86_64_converted_reloc_bit;
}

if (Relocation::isTLS(RType)) {
// No special handling required for TLS relocations on X86.
if (BC->isX86())
if (IsX86)
return;

// The non-got related TLS relocations on AArch64 and RISC-V also could be
Expand Down Expand Up @@ -2661,6 +2663,30 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
return;
}

if (!IsFromCode && !IsWritable && (IsX86 || IsAArch64) &&
Relocation::isPCRelative(RType)) {
BinaryData *BD = BC->getBinaryDataContainingAddress(Rel.getOffset());
if (BD && (BD->nameStartsWith("_ZTV") || // vtable
BD->nameStartsWith("_ZTCN"))) { // construction vtable
BinaryFunction *BF = BC->getBinaryFunctionContainingAddress(
SymbolAddress, /*CheckPastEnd*/ false, /*UseMaxSize*/ true);
if (!BF || BF->getAddress() != SymbolAddress) {
BC->errs()
<< "BOLT-ERROR: the virtual function table entry at offset 0x"
<< Twine::utohexstr(Rel.getOffset());
if (BF)
BC->errs() << " points to the middle of a function @ 0x"
<< Twine::utohexstr(BF->getAddress()) << "\n";
else
BC->errs() << " does not point to any function\n";
exit(1);
}
BC->addRelocation(Rel.getOffset(), BF->getSymbol(), RType, Addend,
ExtractedValue);
return;
}
}

const uint64_t Address = SymbolAddress + Addend;

LLVM_DEBUG({
Expand Down Expand Up @@ -2724,7 +2750,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
const bool IsToCode = ReferencedSection && ReferencedSection->isText();

// Special handling of PC-relative relocations.
if (BC->isX86() && Relocation::isPCRelative(RType)) {
if (IsX86 && Relocation::isPCRelative(RType)) {
if (!IsFromCode && IsToCode) {
// PC-relative relocations from data to code are tricky since the
// original information is typically lost after linking, even with
Expand Down
57 changes: 57 additions & 0 deletions bolt/test/runtime/relative-vftable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Test bolt instrumentation is able to handle relative virtual function table,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/instrumentation/processing/

// i.e., when code is compiled with `-fexperimental-relative-c++-abi-vtables`.

// REQUIRES: system-linux,bolt-runtime
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can drop bolt-runtime without instrumentation.


// RUN: split-file %s %t
// RUN: %clang -fuse-ld=lld -o %t/main.so %t/tt.cpp %t/main.cpp -Wl,-q \
// RUN: -fno-rtti -fexperimental-relative-c++-abi-vtables
// RUN: %t/main.so | FileCheck %s

// CHECK: derived_foo
// CHECK-NEXT: derived_bar
// CHECK-NEXT: derived_goo

// RUN: llvm-bolt %t/main.so -o %t/main.bolted.so --trap-old-code
// RUN: %t/main.bolted.so | FileCheck %s

;--- tt.h
#include <stdio.h>

class Base {
public:
virtual void foo();
virtual void bar();
virtual void goo();
};

class Derived : public Base {
public:
virtual void foo() override;
virtual void bar() override;
virtual void goo() override;
};

;--- tt.cpp
#include "tt.h"
void Derived::goo() { printf("derived_goo\n"); }

;--- main.cpp
#include "tt.h"
#pragma clang optimize off

void Base::foo() { printf("base_foo\n"); }
void Base::bar() { printf("base_bar\n"); }
void Base::goo() { printf("base_goo\n"); }

void Derived::foo() { printf("derived_foo\n"); }
void Derived::bar() { printf("derived_bar\n"); }

int main() {
Derived D;
Base *ptr = &D;
ptr->foo();
ptr->bar();
ptr->goo();
return 0;
}
Loading