动态调度是如何在程序集中发生的

How does dynamic dispatch happen in assembly?

本文关键字:集中 程序集 程序 动态调度      更新时间:2023-10-16

我在某个地方找到了一些代码,并决定在汇编中把它们吐出来,试图找出区别。

#include <iostream>
class A {
    public:
        void f() const { std::cout << "A::f()" << std::endl; }
};
class B {
    public:
        void f() const { std::cout << "B::f()" << std::endl; }
};
int main()
{
    A a ;
    B b ;
    a.f() ;
    b.f() ;
}

-

#include <iostream>
class base {
    public:
        virtual void f() const = 0 ;
        virtual ~base() {}
};
class A : public base {
    public:
        virtual void f() const { std::cout << "A::f()" << std::endl; }
};
class B : public base {
    public:
        virtual void f() const { std::cout << "B::f()" << std::endl; }
};
void dispatch(const base & x) {
    x.f();
}
int main() {
    A a ;
    B b ;
    dispatch(a) ;
    dispatch(b) ;
}

我在研究这个类似的问题(如何通过查看程序集来判断程序是否使用动态调度),并试图在程序集中找到它,但我不清楚

这是两个程序的diff文件(http://www.diffchecker.com/b9y0v3ps)。有人能指出动态调度发生在哪里吗?也许可以解释一下发生了什么以及两者之间的区别?

从链接到的程序集,非虚拟调度如下所示:

53    call _ZNK1A1fEv

直接调用函数。

虚拟调度类似于:

53    mov  EAX, DWORD PTR [EBP - 4]
54    mov  ECX, DWORD PTR [EAX]
56    call DWORD PTR [ECX]

从对象加载vtable的地址,然后从vtable加载函数地址,然后间接调用函数。

动态调度是通过一个虚拟函数表实现的,该表具有完整对象的最终覆盖者的地址。对象本身包含一个指向相应vtable的指针。

在汇编中,您应该能够认识到,对于动态调度,要调用的函数是通过vptr加载的,而在静态调度的情况下,调用直接解析到函数的地址。