Chinaunix首页 | 论坛 | 博客
  • 博客访问: 84877
  • 博文数量: 18
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 321
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-30 21:09
文章分类

全部博文(18)

文章存档

2015年(3)

2014年(9)

2013年(6)

我的朋友

分类: LINUX

2014-01-24 14:26:04

O0版本:
(gdb) disas main
Dump of assembler code for function main:
0x0000000000400758 :    push   %rbp
0x0000000000400759 :    mov    %rsp,%rbp
0x000000000040075c :    push   %rbx
0x000000000040075d :    sub    $0x28,%rsp
//整个类由于没有成员对象和数据,只有一个虚表指针,因此类的大小为8
0x0000000000400761 :    mov    $0x8,%edi
0x0000000000400766 :   callq  0x400658 <_Znwm@plt>
//rax为开辟的内存首地址,调用CChinese的首地址
0x000000000040076b :   mov    %rax,-0x20(%rbp)
0x000000000040076f :   mov    -0x20(%rbp),%rdi
0x0000000000400773 :   callq  0x40093c
0x0000000000400778 :   mov    -0x20(%rbp),%rax
0x000000000040077c :   mov    %rax,-0x10(%rbp)
0x0000000000400780 :   mov    -0x10(%rbp),%rax
0x0000000000400784 :   mov    (%rax),%rax
//根据(一)的分析,有两个析构函数,因此ShowSpeak在虚表中处于第三项,因此这里的偏移量就是0x10
0x0000000000400787 :   add    $0x10,%rax
0x000000000040078b :   mov    (%rax),%rax
0x000000000040078e :   mov    -0x10(%rbp),%rdi
0x0000000000400792 :   mov    $0x0,%esi
0x0000000000400797 :   callq  *%rax
0x0000000000400799 :   cmpq   $0x0,-0x10(%rbp)
0x000000000040079e :   jne    0x4007c0
0x00000000004007a0 :   jmp    0x4007d4
0x00000000004007a2 :   mov    %rax,-0x28(%rbp)
0x00000000004007a6 :   mov    -0x28(%rbp),%rbx
0x00000000004007aa :   mov    -0x20(%rbp),%rdi
0x00000000004007ae :   callq  0x400628 <_ZdlPv@plt>
0x00000000004007b3 :   mov    %rbx,-0x28(%rbp)
0x00000000004007b7 :   mov    -0x28(%rbp),%rdi
0x00000000004007bb :   callq  0x400668 <_Unwind_Resume@plt>
0x00000000004007c0 :  mov    -0x10(%rbp),%rax
0x00000000004007c4 :  mov    (%rax),%rax
//调用第二个析构函数
0x00000000004007c7 :  add    $0x8,%rax
0x00000000004007cb :  mov    (%rax),%rax
0x00000000004007ce :  mov    -0x10(%rbp),%rdi
0x00000000004007d2 :  callq  *%rax
0x00000000004007d4 :  mov    $0x0,%eax
0x00000000004007d9 :  add    $0x28,%rsp
0x00000000004007dd :  pop    %rbx
0x00000000004007de :  leaveq 
0x00000000004007df :  retq   

O2版本:
0x0000000000400760 :    mov    %rbx,-0x18(%rsp)
0x0000000000400765 :    mov    %rbp,-0x10(%rsp)
0x000000000040076a :   mov    $0x8,%edi
0x000000000040076f :   mov    %r12,-0x8(%rsp)
0x0000000000400774 :   sub    $0x18,%rsp
//前面这一串动作的目的是为了保存某些寄存器的值,唯一有意义的就是mov $0x8,%edi,表明需要开辟的空间大小为8个字节
0x0000000000400778 :   callq  0x400658 <_Znwm@plt>
//%rax里面保存了这块内存的首地址,因此需要首先知道这个rbp到底是哪个函数的地址?
//0x464(%rip),这个在这里有点绕口,相当于将0x464+$rip的值作为内存地址,将该内存单元里面的值取出来,放到$rbp中
//注意这里的$rip的值是下一条指令的值,所以是0x400784+0x464=0x400be8
//%rbp的值是0x400820,该地址处的指令为
//0x400820 <_ZN7CPerson12GetClassNameEv>: mov    $0x400b10,%eax
//0x400825 <_ZN7CPerson12GetClassNameEv+5>:       retq   
//其中,0x400b10里面的值是“CPerson”
//这个0x400bd0是CPerson的虚表指针,可以通过x/6xg 0x400bd0来查看表项内容,并通过反汇编每个表项所指地址处的汇编来判断每个虚函数的内容

//从这里可以看出,经过优化后,没有了明显的构造函数,相当于构造函数被打开了,在main段就将CPerson构造函数需要做的事情都做掉了;但首部的虚表指针,还是赋了一下
0x000000000040077d :   mov    0x464(%rip),%rbp        # 0x400be8 <_ZTV7CPerson+40>
0x0000000000400784 :   mov    %rax,%rbx
0x0000000000400787 :   movq   $0x400bd0,(%rax)
0x000000000040078e :   mov    %rax,%rdi
0x0000000000400791 :   callq  *%rbp
//这里的rax是函数返回的内容,0x400b22的值是"%s::ShowSpeak()\r\n",因此猜测rax就是返回的GetClassName()返回的字符串
0x0000000000400793 :   mov    %rax,%rsi
0x0000000000400796 :   mov    $0x400b22,%edi
0x000000000040079b :   xor    %eax,%eax
0x000000000040079d :   callq  0x400618

//目前的分析来看,0x400b50像是CChinese的虚表地址
0x00000000004007a2 :   movq   $0x400b50,(%rbx)
0x00000000004007a9 :   mov    %rbx,%rdi
//就是两行代码
//mov    $0x400b18,%eax;retq;
//其中0x400b18的内容为“CChinese”
0x00000000004007ac :   callq  *0x3b6(%rip)        # 0x400b68 <_ZTV8CChinese+40>
0x00000000004007b2 :   mov    %rax,%rsi
0x00000000004007b5 :   mov    $0x400b22,%edi
0x00000000004007ba :   xor    %eax,%eax
0x00000000004007bc :   callq  0x400618
//下面这几行,就是开始调用ShowSpeak了
0x00000000004007c1 :   mov    (%rbx),%rax
0x00000000004007c4 :  mov    %rbx,%rdi
0x00000000004007c7 :  xor    %esi,%esi
0x00000000004007c9 :  callq  *0x10(%rax)
//这里开始调用析构函数了
0x00000000004007cc :  mov    (%rbx),%rax
0x00000000004007cf :  mov    %rbx,%rdi
0x00000000004007d2 :  callq  *0x8(%rax)
0x00000000004007d5 :  mov    (%rsp),%rbx
0x00000000004007d9 :  mov    0x8(%rsp),%rbp
//平衡堆栈,清理现场了
0x00000000004007de :  xor    %eax,%eax
0x00000000004007e0 :  mov    0x10(%rsp),%r12
0x00000000004007e5 :  add    $0x18,%rsp
0x00000000004007e9 :  retq   
//到这里main函数就结束了
0x00000000004007ea :  mov    %rax,%r12
0x00000000004007ed :  mov    %rbx,%rdi
0x00000000004007f0 :  callq  0x400628 <_ZdlPv@plt>
0x00000000004007f5 :  mov    %r12,%rdi
0x00000000004007f8 :  callq  0x400668 <_Unwind_Resume@plt>
0x00000000004007fd :  mov    %rbx,%rdi
0x0000000000400800 :  mov    %rax,%r12
0x0000000000400803 :  movq   $0x400bd0,(%rbx)
0x000000000040080a :  callq  *%rbp
0x000000000040080c :  mov    $0x400b21,%edi
0x0000000000400811 :  mov    %rax,%rsi
0x0000000000400814 :  xor    %eax,%eax
0x0000000000400816 :  callq  0x400618
0x000000000040081b :  jmp    0x4007ed


阅读(1403) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~