编译器是如何用汇编语言实现C++的虚函数表和隐式传递this指针(三)

来源:互联网 发布:推荐等身大抱枕淘宝店 编辑:程序博客网 时间:2024/05/16 08:25
//直接来个复杂的多重继承#include <stdio.h>class Base{public:     Base(){        puts("Base()");    }    virtual void fun1()    {        puts("Base::fun1()");    }    virtual void fun2()    {        puts("Base::fun2()");    }    virtual void fun3()    {        puts("Base::fun3()");    }    void fun4(){        printf("Normal Base::fun4()\n");    }    ~Base(){        puts("~Base()");    }};class Base2{public:    Base2(){        puts("Base2()");    }    virtual void foo1(){        puts("Base2::foo1()");    }    virtual void foo2(){        puts("Base2::foo2()");    }    ~Base2(){        puts("~Base2()");    }};class Base3{public:    Base3(){        puts("Base3()");    }    virtual void bar1(){        puts("Base3::bar1()");    }    ~Base3(){        puts("~Base3()");    }};class Derive : public Base,public Base2,public Base3{public:     Derive()    {        puts("Derive()");    }    void fun1()    {        puts("Derive::fun1()");    }    void fun2()    {        puts("Derive::fun2()");    }    void foo1()    {        puts("Derive::foo1()");    }/*    void fun3()    {        puts("Derive::fun3()");    }  */      void fun4(){        printf("Normal Derive::fun4()\n");    }    ~Derive(){        puts("~Derive()");    }};typedef void (*FUN) (void);int main(){    FUN pfun1 = NULL;    FUN pfun2 = NULL;    FUN pfun3 = NULL;    FUN pfun4 = NULL;    FUN pfun5 = NULL;    FUN pfun6 = NULL;    Base * pb = NULL;    Base2 *pb2 = NULL;    Base3 *pb3 = NULL;    Derive b;    printf("sizeof b = %d\n",sizeof b);    printf("&b = %p\n",(&b));    printf("vtable = %p\n",(int *)(&b));    printf("*vtable = %p\n",**(int **)(&b));    printf("b = %p\n",*(int*)(&b));     //使用两种情况调用比对   /*    pb = &b;    pb->fun1();    pb->fun2();    pb->fun3();    pb2 = &b;    pb2->foo1();    pb2->foo2();    pb3 = &b;    pb3->bar1();*/        pfun1 = (FUN)**(int**)(&b);    pfun1();    pfun2 = (FUN)*(*(int**)(&b)+1);    pfun2();    pfun3 = (FUN)*(*(int**)(&b)+2);    pfun3();    pfun4 = (FUN)*(*((int**)(&b)+1));    pfun4();    pfun5 = (FUN)*(*((int**)(&b)+1)+1);    pfun5();    pfun6 = (FUN)*(*((int**)(&b)+2));    pfun6();    return 0;}/*Base()Base2()Base3()Derive()sizeof b = 12 //保存三个虚函数表的地址 &b = 0xbfecb770vtable = 0xbfecb770*vtable = 0x80488fab = 0x8048be8Derive::fun1()Derive::fun2()Base::fun3()Derive::foo1()Base2::foo2()Base3::bar1()~Derive()~Base3()~Base2()~Base()汇编的代码很长但是关键的地方在Derive的构造函数,这里只给出最关键的几行...call_ZN5Base3C2Ev.LEHE2:movl8(%ebp), %eax              #this   下面是对 b的12个字节赋值movl$_ZTV6Derive+8, (%eax)     #vtable1 movl8(%ebp), %eaxmovl$_ZTV6Derive+32, 4(%eax)   #vtable2movl8(%ebp), %eaxmovl$_ZTV6Derive+48, 8(%eax)   #vtable3movl$.LC12, (%esp)....globl main.typemain, @functionmain:...leal16(%esp), %eax      #this  即指向vtables的指针movl(%eax), %eax        #vtable1movl(%eax), %eax        #_ZN6Derive4fun1Ev Derive::fun1()movl%eax, 28(%esp)movl28(%esp), %eaxcall*%eaxleal16(%esp), %eax     #thismovl(%eax), %eaxaddl$4, %eax           #_ZN6Derive4fun2Ev Derive::fun2()movl(%eax), %eaxmovl%eax, 32(%esp)movl32(%esp), %eaxcall*%eaxleal16(%esp), %eaxmovl(%eax), %eaxaddl$8, %eaxmovl(%eax), %eaxmovl%eax, 36(%esp)movl36(%esp), %eaxcall*%eaxleal16(%esp), %eax      #this 即指向vtables的指针addl$4, %eax            #eax 保存vtable2的地址movl(%eax), %eax        #eax 解引用得到vtable2movl(%eax), %eax        #eax _ZThn4_N6Derive4foo1Ev    movl%eax, 40(%esp)movl40(%esp), %eaxcall*%eaxleal16(%esp), %eaxaddl$4, %eaxmovl(%eax), %eaxaddl$4, %eaxmovl(%eax), %eax        #_ZN5Base24foo2Evmovl%eax, 44(%esp)movl44(%esp), %eaxcall*%eaxleal16(%esp), %eax    #this 即指向vtables的指针addl$8, %eax          #eax 保存vtable3的地址movl(%eax), %eax      #eax 解引用得到vtable3movl(%eax), %eax      #_ZN5Base34bar1Ev  movl%eax, 48(%esp)movl48(%esp), %eaxcall*%eax....size_ZTV6Derive, 52_ZTV6Derive:.long0.long_ZTI6Derive.long_ZN6Derive4fun1Ev       #vtable1 _ZTV6Derive+8.long_ZN6Derive4fun2Ev.long_ZN4Base4fun3Ev.long_ZN6Derive4foo1Ev.long-4.long_ZTI6Derive.long_ZThn4_N6Derive4foo1Ev  #vtable2 _ZTV6Derive+32.long_ZN5Base24foo2Ev   .long-8.long_ZTI6Derive.long_ZN5Base34bar1Ev        #vtable3 _ZTV6Derive+48...使用注释部分调用的汇编代码是:...movl$0, 52(%esp) #Base * pb = NULL;movl$0, 56(%esp) #Base2 *pb2 = NULL;movl$0, 60(%esp) #Base3 *pb3 = NULL;...leal16(%esp), %eaxmovl%eax, 52(%esp)  #(%eax)即保存地址 $_ZTV6Derive+8,       #vtable1  pb1 = &b;leal16(%esp), %eaxaddl$4, %eax        # 4(%eax)即保存地址 $_ZTV6Derive+32,    #vtable2movl%eax, 56(%esp)  # pb3 = &b;    leal16(%esp), %eaxaddl$8, %eax        # 8(%eax)即保存地址 $_ZTV6Derive+48,    #vtable3 movl%eax, 60(%esp)  # pb3 = &b;     #基类指针只保存对应的经过子类调整(是否重定义虚函数)虚函数表...   movl52(%esp), %eax  #pb 中保存vtable1虚表movl(%eax), %eaxmovl(%eax), %edxmovl52(%esp), %eaxmovl%eax, (%esp)   #将this保存到栈中,这就是多态时隐式传递的this指针指向子类的   在上面的调用中没有这一步this指针隐式传参call*%edx          #pb->fun1(); movl52(%esp), %eaxmovl(%eax), %eaxaddl$4, %eax       #获得_ZN6Derive4fun2Ev 的地址movl(%eax), %edx   #得到_ZN6Derive4fun2Ev函数地址movl52(%esp), %eaxmovl%eax, (%esp)call*%edx         #pb->fun2();movl52(%esp), %eaxmovl(%eax), %eaxaddl$8, %eaxmovl(%eax), %edxmovl52(%esp), %eaxmovl%eax, (%esp)call*%edx        #pb->fun3();  movl56(%esp), %eax #pb2movl(%eax), %eaxmovl(%eax), %edxmovl56(%esp), %eaxmovl%eax, (%esp)call*%edx          # pb2->foo1();movl56(%esp), %eaxmovl(%eax), %eaxaddl$4, %eaxmovl(%eax), %edxmovl56(%esp), %eaxmovl%eax, (%esp)call*%edx          #pb2->foo2();movl60(%esp), %eax #pb3movl(%eax), %eaxmovl(%eax), %edxmovl60(%esp), %eaxmovl%eax, (%esp)call*%edx          #pb3->bar1();*/

原创粉丝点击