I'm doing some profiling for virtual function call performance and when read the perf report, I got this:
mov (%rbx),%rdi # move "this" pointer to %rdi
mov (%rdi),%rax # move vtable pointer to %rax
mov %rbp,%rsi # move first virtual function parameter to %rsi
callq *38 # absolute address call? why?
It calls virtual function via callq *38, I've tried to search AT&T assembly syntax manual and find out this is an absolute address function call which jumps to absolute address 38, my question is why it uses absolute address here instead of getting the address from vtable entries(via %rax)?
I'm using perf version 4.15.18, and objdump shows me:
48 8b 3b mov (%rbx),%rdi
48 8b 07 mov (%rdi),%rax
48 89 ee mov %rbp,%rsi
ff 50 38 callq *0x38(%rax)
48 83 c3 08 add %0x8,%rbx
Example code to reproduce the problem under my test environment:
#include <vector>
struct A {
virtual int v1(int x) {
return x+1;
}
virtual int v2(int x) {
return x+2;
}
virtual int v3(int x) {
return x+3;
}
};
struct B:A {
int v3(int x) override {
return x+4;
}
};
struct C:A {
int v2(int x) override {
return x+5;
}
};
int main(){
B b;
C c;
std::vector<A*> vs = {&b, &c};
int t = 0;
while (true) {
t = vs[0]->v3(t);
t = vs[1]->v3(t);
}
return 0;
}
Compiled with g++ 7.5.0 via g++ test.cc -O3, perf 4.15.18 shows:
...
mov %eax,%esi
mov (%rbx),%rdi
mov (%rdi),%rdx
callq *10
mov 0x8(%rbx),%rdi
mov %eax,%esi
mov (%rdi),%rdx
callq *10
jmp 68
...
objdump shows:
89 c6 mov %eax,%esi
48 8b 3b mov (%rbx),%rdi
48 8b 17 mov (%rdi),rdx
ff 52 10 callq *0x10(%rdx)
48 8b 7b 08 mov 0x8(%rbx),%rdi
89 c6 mov %eax,%esi
48 8b 17 mov (%rdi),rdx
ff 52 10 callq *0x10(%rdx)