反汇编五:类对象存储结构

this指针

在这里插入图片描述
在这里插入图片描述
this指针是常指针
常对象的this指针是指向常量的常指针
由于this指针隐藏传参,所以常对象不能调用普通成员函数

普通成员

在这里插入图片描述

静态数据成员

在这里插入图片描述

类对象 做返回值或参数 值传递 不一定调用构造函数


1.类对象做参数:
没显式调用默认构造函数
逐成员复制到栈上
先定义后压栈

2.类对象 做返回值:
在这里插入图片描述

3.何时提供默认构造函数
在这里插入图片描述

隐藏的虚表和虚表指针


虚表指针:对象前4字节为虚表指针
虚表:虚表保存类定义的虚函数地址,先定义的虚函数排在前面

构造函数

虚表初始化:构造函数取得虚表地址保存在虚表指针

虚指针重写:
在这里插入图片描述
64位系统实例

Derived d;//源码
main函数调用Derived构造函数
   0x0000000000400c3b <+23>:    lea    -0x40(%rbp),%rax
   0x0000000000400c3f <+27>:    mov    %rax,%rdi 
   //通过rdi寄存器传栈变量首地址给构造函数初始化
   0x0000000000400c42 <+30>:    callq  0x400af8 <Derived::Derived()> 
   //直接调用
Dump of assembler code for function Derived::Derived():
   0x0000000000400af8 <+0>:     push   %rbp
   0x0000000000400af9 <+1>:     mov    %rsp,%rbp
   0x0000000000400afc <+4>:     push   %rbx
   0x0000000000400afd <+5>:     sub    $0x18,%rsp
   0x0000000000400b01 <+9>:     mov    %rdi,-0x18(%rbp)  
   //待构造变量的首地址
   0x0000000000400b05 <+13>:    mov    -0x18(%rbp),%rax 
   0x0000000000400b09 <+17>:    mov    %rax,%rdi   
   //再次传给base
   0x0000000000400b0c <+20>:    callq  0x400a1e <Base::Base()>
   0x0000000000400b11 <+25>:    mov    -0x18(%rbp),%rax
   0x0000000000400b15 <+29>:    movq   $0x400e90,(%rax) 
   //虚表指针重写
   //没有参数列表
   0x0000000000400b1c <+36>:    mov    $0x400e4e,%esi  
   //构造函数的函数体
   0x0000000000400b21 <+41>:    mov    $0x6020e0,%edi
   0x0000000000400b26 <+46>:    callq  0x4008d0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x0000000000400b2b <+51>:    mov    $0x4008f0,%esi
   0x0000000000400b30 <+56>:    mov    %rax,%rdi
   0x0000000000400b33 <+59>:    callq  0x4008e0 <_ZNSolsEPFRSoS_E@plt>
   0x0000000000400b38 <+64>:    jmp    0x400b54 <Derived::Derived()+92>    
   //像是根据函数体执行结果,可能失败,就回滚前面创建的base
   0x0000000000400b3a <+66>:    mov    %rax,%rbx
   0x0000000000400b3d <+69>:    mov    -0x18(%rbp),%rax
   0x0000000000400b41 <+73>:    mov    %rax,%rdi
   0x0000000000400b44 <+76>:    callq  0x400a5e <Base::~Base()>
   0x0000000000400b49 <+81>:    mov    %rbx,%rax
   0x0000000000400b4c <+84>:    mov    %rax,%rdi
   0x0000000000400b4f <+87>:    callq  0x400920 <_Unwind_Resume@plt>
   0x0000000000400b54 <+92>:    add    $0x18,%rsp  //恢复栈结构
   0x0000000000400b58 <+96>:    pop    %rbx
   0x0000000000400b59 <+97>:    pop    %rbp
   0x0000000000400b5a <+98>:    retq
Dump of assembler code for function Base::Base():
   0x0000000000400a1e <+0>:     push   %rbp
   0x0000000000400a1f <+1>:     mov    %rsp,%rbp
   0x0000000000400a22 <+4>:     sub    $0x10,%rsp
   0x0000000000400a26 <+8>:     mov    %rdi,-0x8(%rbp) 
   //传入的待构造变量地址
   0x0000000000400a2a <+12>:    mov    -0x8(%rbp),%rax
   0x0000000000400a2e <+16>:    movq   $0x400ed0,(%rax) 
   //虚表地址初始化
   //首地址=this=虚表指针
   0x0000000000400a35 <+23>:    mov    -0x8(%rbp),%rax
   //初始化列表的代码
   0x0000000000400a39 <+27>:    movl   $0x6666,0x8(%rax)
=> 0x0000000000400a40 <+34>:    mov    $0x400e30,%esi 
   //构造函数的函数体
   0x0000000000400a45 <+39>:    mov    $0x6020e0,%edi 
   0x0000000000400a4a <+44>:    callq  0x4008d0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x0000000000400a4f <+49>:    mov    $0x4008f0,%esi
   0x0000000000400a54 <+54>:    mov    %rax,%rdi
   0x0000000000400a57 <+57>:    callq  0x4008e0 <_ZNSolsEPFRSoS_E@plt>
   0x0000000000400a5c <+62>:    leaveq
   0x0000000000400a5d <+63>:    retq
End of assembler dump.

在这里插入图片描述

析构函数

还原虚表指针:
在这里插入图片描述
在这里插入图片描述
看反汇编码,析构函数在保存bp,获取析构对象首地址后,就回写虚表

Dump of assembler code for function Derived::~Derived():
   0x0000000000400b5c <+0>:     push   %rbp
   0x0000000000400b5d <+1>:     mov    %rsp,%rbp
   0x0000000000400b60 <+4>:     push   %rbx
   0x0000000000400b61 <+5>:     sub    $0x18,%rsp
   0x0000000000400b65 <+9>:     mov    %rdi,-0x18(%rbp)
   0x0000000000400b69 <+13>:    mov    -0x18(%rbp),%rax
   //成员对象为空
   //设置虚表
   0x0000000000400b6d <+17>:    movq   $0x400e90,(%rax)
   //函数体
...........
   //父类析构函数
   0x0000000000400b90 <+52>:    mov    -0x18(%rbp),%rax
   0x0000000000400b94 <+56>:    mov    %rax,%rdi
   0x0000000000400b97 <+59>:    callq  0x400a5e <Base::~Base()>
   //析构子类数据
   //会有类似语句:
   //jmp    0x400bcd <Derived::~Derived()+113>
   //<_ZdlPv@plt>   分析见下面
.........
   0x0000000000400bcd <+113>:   add    $0x18,%rsp
   0x0000000000400bd1 <+117>:   pop    %rbx
   0x0000000000400bd2 <+118>:   pop    %rbp
   0x0000000000400bd3 <+119>:   retq
End of assembler dump.
Dump of assembler code for function Base::~Base():
   0x0000000000400a5e <+0>:     push   %rbp
   0x0000000000400a5f <+1>:     mov    %rsp,%rbp
   0x0000000000400a62 <+4>:     sub    $0x10,%rsp
   0x0000000000400a66 <+8>:     mov    %rdi,-0x8(%rbp)
   0x0000000000400a6a <+12>:    mov    -0x8(%rbp),%rax
   //成员对象为空
   //设置虚表
   0x0000000000400a6e <+16>:    movq   $0x400ed0,(%rax)
........函数体
   0x0000000000400a91 <+51>:    mov    $0x0,%eax
   0x0000000000400a96 <+56>:    test   %eax,%eax
   0x0000000000400a98 <+58>:    je     0x400aa6 <Base::~Base()+72>
   0x0000000000400a9a <+60>:    mov    -0x8(%rbp),%rax
   0x0000000000400a9e <+64>:    mov    %rax,%rdi
   0x0000000000400aa1 <+67>:    callq  0x400880 <_ZdlPv@plt> //见下面
   0x0000000000400aa6 <+72>:    leaveq
   0x0000000000400aa7 <+73>:    retq
End of assembler dump.

<_ZdlPv@plt>

_ZdlPv@plt
再看main反汇编析构部分

   0x0000000000400cbd <+153>:   mov    -0x18(%rbp),%rax
   0x0000000000400cc1 <+157>:   mov    (%rax),%rax
   0x0000000000400cc4 <+160>:   add    $0x8,%rax       //虚表偏移8 
   0x0000000000400cc8 <+164>:   mov    (%rax),%rax
   0x0000000000400ccb <+167>:   mov    -0x18(%rbp),%rdx
   0x0000000000400ccf <+171>:   mov    %rdx,%rdi
   0x0000000000400cd2 <+174>:   callq  *%rax        // delete   pb;
   0x0000000000400cd4 <+176>:   mov    $0x0,%ebx
   0x0000000000400cd9 <+181>:   lea    -0x40(%rbp),%rax
   0x0000000000400cdd <+185>:   mov    %rax,%rdi
   0x0000000000400ce0 <+188>:   callq  0x400b5c <Derived::~Derived()>    //栈变量d析构

derive的析构函数有2个
1、0x400b5c Derived::~Derived() (偏移0字节)
2、虚表偏移8字节

函数2调用函数1,并调用
callq 0x400880 _ZdlPv@plt
函数1为:

(gdb) disassemble  0x00400b5c
Dump of assembler code for function Derived::~Derived():
..........保存调用栈.....
..........rdi中取得入参--隐藏的待析构对象地址.....
..........还原虚表.....
..........函数体......
   0x0000000000400b90 <+52>:    mov    -0x18(%rbp),%rax
   0x0000000000400b94 <+56>:    mov    %rax,%rdi
   0x0000000000400b97 <+59>:    callq  0x400a5e <Base::~Base()>
   0x0000000000400b9c <+64>:    mov    $0x0,%eax
   0x0000000000400ba1 <+69>:    test   %eax,%eax
   0x0000000000400ba3 <+71>:    je     0x400bcd <Derived::~Derived()+113>
   0x0000000000400ba5 <+73>:    mov    -0x18(%rbp),%rax
   0x0000000000400ba9 <+77>:    mov    %rax,%rdi
   0x0000000000400bac <+80>:    callq  0x400880 <_ZdlPv@plt>
   0x0000000000400bb1 <+85>:    jmp    0x400bcd <Derived::~Derived()+113>
   0x0000000000400bb3 <+87>:    mov    %rax,%rbx
   0x0000000000400bb6 <+90>:    mov    -0x18(%rbp),%rax
   0x0000000000400bba <+94>:    mov    %rax,%rdi
   0x0000000000400bbd <+97>:    callq  0x400a5e <Base::~Base()>
   0x0000000000400bc2 <+102>:   mov    %rbx,%rax
   0x0000000000400bc5 <+105>:   mov    %rax,%rdi
   0x0000000000400bc8 <+108>:   callq  0x400920 <_Unwind_Resume@plt>
   0x0000000000400bcd <+113>:   add    $0x18,%rsp
   0x0000000000400bd1 <+117>:   pop    %rbx
   0x0000000000400bd2 <+118>:   pop    %rbp
   0x0000000000400bd3 <+119>:   retq
End of assembler dump.

(待补充。。。。
mov $0x0,%eax
test %eax,%eax
je 0x400bcd Derived::~Derived()+113
这些命令,实际执行时会跳转

虚析构函数:
在这里插入图片描述

多态


指针对象通过虚表间接调用虚函数
普通对象直接调用自己定义的函数

    Base b;
    Derived d;
    ....
    d.f();
    .....
    pb=&b;
    pb->f();
   0x0000000000400c5b <+55>:    lea    -0x40(%rbp),%rax
   0x0000000000400c5f <+59>:    mov    %rax,%rdi
   0x0000000000400c62 <+62>:    callq  0x400bfa <Derived::f()>                  //d.f();
   0x0000000000400c67 <+67>:    lea    -0x30(%rbp),%rax  //pb=&b;
   0x0000000000400c6b <+71>:    mov    %rax,-0x18(%rbp) 
   0x0000000000400c6f <+75>:    mov    -0x18(%rbp),%rax  
   0x0000000000400c73 <+79>:    mov    (%rax),%rax    //取虚表
   0x0000000000400c76 <+82>:    add    $0x10,%rax                   
   //虚表偏移10
   0x0000000000400c7a <+86>:    mov    (%rax),%rax
   0x0000000000400c7d <+89>:    mov    -0x18(%rbp),%rdx
   0x0000000000400c81 <+93>:    mov    %rdx,%rdi
   0x0000000000400c84 <+96>:    callq  *%rax                          
   //pb->f();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值