Assembly code for C++ virtual function call in perf report?

Viewed 98

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)
0 Answers
Related