
To handle relative vftable, which is enabled with clang option `-fexperimental-relative-c++-abi-vtables`, we look for PC relative relocations whose fixup locations fall in vtable address ranges. For such relocations, actual target is just virtual function itself, and the addend is to record the distance between vtable slot for target virtual function and the first virtual function slot in vtable, which is to match generated code that calls virtual function. So we can skip the logic of handling "function + offset" and directly save such relocations for future fixup after new layout is known.
58 lines
1.2 KiB
C++
58 lines
1.2 KiB
C++
// Test BOLT is able to handle relative virtual function table, i.e., when
|
|
// code is compiled with `-fexperimental-relative-c++-abi-vtables`.
|
|
|
|
// REQUIRES: system-linux
|
|
|
|
// 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;
|
|
}
|