前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《coredump问题原理探究》Linux x86版6.6节单继承

《coredump问题原理探究》Linux x86版6.6节单继承

作者头像
血狼debugeeker
发布2018-09-20 14:45:13
3500
发布2018-09-20 14:45:13
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344555

在C++里,类的多态是通过继承由虚函数来体现的。那么在单继承中,类的成员变量和虚函数的分布又是怎样的呢?

看一下例子:

  1	 #include <stdio.h>
  2	 class xuzhina_dump_c06_s4_base
  3	 {
  4	     private:
  5	         int m_a;
  6	     public:
  7	         xuzhina_dump_c06_s4_base() { m_a = 1; }
  8	         virtual void inc()
  9	         {
 10	             m_a++;
 11	         }
 12	         virtual void print()
 13	         {
 14	             printf( "m_a:%d\n", m_a );
 15	         }
 16	 };
 17 
 18	 class xuzhina_dump_c06_s4_derived: public xuzhina_dump_c06_s4_base
 19	 {
 20	     private:
 21	         int m_b;
 22	         int m_c;
 23	     public:
 24	         xuzhina_dump_c06_s4_derived()
 25	         {
 26	             m_b = 0;
 27	             m_c = 2*m_b;
 28	         }
 29	         virtual void mul()
 30	         {
 31	             m_c *= m_b;
 32	         }
 33	 
 34	         virtual void print()
 35	         {
 36	             printf( "m_b:%d, m_c:%d\n", m_b, m_c );
 37	         }
 38	         virtual void dec()
 39	         {
 40	             m_c -= m_b;
 41	         }
 42
43	         virtual void inc()
 44	         {
 45	             m_b++;
 46	             m_c += m_b;
 47	         }
 48	 };
 49 
 50	 int main()
 51	 {
 52	     xuzhina_dump_c06_s4_base* p = new xuzhina_dump_c06_s4_derived;
 53	     if ( p != NULL )
 54	     {
 55	         p->inc();
 56	         p->print();
 57	     }
 58 
 59	     return 0;
 60	 }

看一下汇编:

(gdb) disassemble main
Dump of assembler code for function main:
   0x080485b0 <+0>:     push   %ebp
   0x080485b1 <+1>:     mov    %esp,%ebp
   0x080485b3 <+3>:     push   %ebx
   0x080485b4 <+4>:     and    $0xfffffff0,%esp
   0x080485b7 <+7>:     sub    $0x20,%esp
   0x080485ba <+10>:    movl   $0x10,(%esp)
   0x080485c1 <+17>:    call   0x80484a0 <_Znwj@plt>
   0x080485c6 <+22>:    mov    %eax,%ebx
   0x080485c8 <+24>:    mov    %ebx,(%esp)
   0x080485cb <+27>:    call   0x8048654 <_ZN27xuzhina_dump_c06_s4_derivedC2Ev>
   0x080485d0 <+32>:    mov    %ebx,0x1c(%esp)
   0x080485d4 <+36>:    cmpl   $0x0,0x1c(%esp)
   0x080485d9 <+41>:    je     0x8048600 <main+80>
   0x080485db <+43>:    mov    0x1c(%esp),%eax
   0x080485df <+47>:    mov    (%eax),%eax
   0x080485e1 <+49>:    mov    (%eax),%eax
   0x080485e3 <+51>:    mov    0x1c(%esp),%edx
   0x080485e7 <+55>:    mov    %edx,(%esp)
   0x080485ea <+58>:    call   *%eax
   0x080485ec <+60>:    mov    0x1c(%esp),%eax
   0x080485f0 <+64>:    mov    (%eax),%eax
   0x080485f2 <+66>:    add    $0x4,%eax
   0x080485f5 <+69>:    mov    (%eax),%eax
   0x080485f7 <+71>:    mov    0x1c(%esp),%edx
   0x080485fb <+75>:    mov    %edx,(%esp)
   0x080485fe <+78>:    call   *%eax
   0x08048600 <+80>:    mov    $0x0,%eax
   0x08048605 <+85>:    mov    -0x4(%ebp),%ebx
   0x08048608 <+88>:    leave  
   0x08048609 <+89>:    ret    
End of assembler dump.

由上一节可知,要看虚函数表和成员变量的内存布局,直接看构造函数的汇编就行了。

(gdb) disassemble _ZN27xuzhina_dump_c06_s4_derivedC2Ev
Dump of assembler code for function _ZN27xuzhina_dump_c06_s4_derivedC2Ev:
   0x08048654 <+0>:     push   %ebp
   0x08048655 <+1>:     mov    %esp,%ebp
   0x08048657 <+3>:     sub    $0x18,%esp
   0x0804865a <+6>:     mov    0x8(%ebp),%eax
   0x0804865d <+9>:     mov    %eax,(%esp)
   0x08048660 <+12>:    call   0x804860a <_ZN24xuzhina_dump_c06_s4_baseC2Ev>
   0x08048665 <+17>:    mov    0x8(%ebp),%eax
   0x08048668 <+20>:    movl   $0x80487c8,(%eax)
   0x0804866e <+26>:    mov    0x8(%ebp),%eax
   0x08048671 <+29>:    movl   $0x0,0x8(%eax)
   0x08048678 <+36>:    mov    0x8(%ebp),%eax
   0x0804867b <+39>:    mov    0x8(%eax),%eax
   0x0804867e <+42>:    lea    (%eax,%eax,1),%edx
   0x08048681 <+45>:    mov    0x8(%ebp),%eax
   0x08048684 <+48>:    mov    %edx,0xc(%eax)
   0x08048687 <+51>:    leave  
   0x08048688 <+52>:    ret    
End of assembler dump.

可见,类xuzhina_dump_c06_s4_derived的构造函数,先调用基类xuzhina_dump_c06_s4_base构造函数(即_ZN24xuzhina_dump_c06_s4_baseC2Ev),再设置虚函数表,然后初始化自己变量。在这里,有两个疑问:

1.      类xuzhina_dump_c06_s4_derived的成员变量是从this+8的位置开始的,而不是从this+4的位置开始.那么this+4放着什么东西?

2.      虚函数表指针0x80487c8放着的是类xuzhina_dump_c06_s4_derived的虚函数表,还是基类xuzhina_dump_c06_s4_base的虚函数表?

在回答这两个问题之前,先看一下基类xuzhina_dump_c06_s4_base的构造函数:

(gdb) disassemble _ZN24xuzhina_dump_c06_s4_baseC2Ev
Dump of assembler code for function _ZN24xuzhina_dump_c06_s4_baseC2Ev:
   0x0804860a <+0>:     push   %ebp
   0x0804860b <+1>:     mov    %esp,%ebp
   0x0804860d <+3>:     mov    0x8(%ebp),%eax
   0x08048610 <+6>:     movl   $0x80487e0,(%eax)
   0x08048616 <+12>:    mov    0x8(%ebp),%eax
   0x08048619 <+15>:    movl   $0x1,0x4(%eax)
   0x08048620 <+22>:    pop    %ebp
   0x08048621 <+23>:    ret    
End of assembler dump.

从基类的构造函数可知,上面两个疑问的答案如下:

1.      this+4的地方是存放着m_a,初始化为1.

2.      地址0x80487e0放着的则是基类的虚函数表。而地址0x80487c8放着的是子类的虚函数表。

看一下这两个虚函数表指针的内容。

基类虚函数表指针:

(gdb)  x /4wx 0x80487e0
0x80487e0 <_ZTV24xuzhina_dump_c06_s4_base+8>:   0x08048622      0x08048636      0x75783732      0x6e69687a
(gdb) info symbol 0x08048622
xuzhina_dump_c06_s4_base::inc() in section .text
(gdb) info symbol 0x08048636
xuzhina_dump_c06_s4_base::print() in section .text

子类虚函数表指针:

(gdb) x /8wx 0x80487c8
0x80487c8 <_ZTV27xuzhina_dump_c06_s4_derived+8>:        0x080486e6      0x080486a4      0x0804868a      0x080486cc
0x80487d8 <_ZTV24xuzhina_dump_c06_s4_base>:     0x00000000      0x08048830      0x08048622      0x08048636
(gdb) info symbol 0x080486e6
xuzhina_dump_c06_s4_derived::inc() in section .text
(gdb) info symbol 0x080486a4
xuzhina_dump_c06_s4_derived::print() in section .text
(gdb) info symbol 0x0804868a
xuzhina_dump_c06_s4_derived::mul() in section .text
(gdb) info symbol 0x080486cc
xuzhina_dump_c06_s4_derived::dec() in section .text

也就是说子类xuzhina_dump_c06_s4_derived的对象构造经历了下面的步骤

由上面可以看到子类虚函数表的分布规律:

1.重载基类的虚函数,按照基类虚函数的声明顺序排列,和子类声明顺序无关。

2.子类独有的虚函数,按照虚函数的声明顺序排列,追加在重载虚函数后面。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015年02月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档