0

我们如何使用 objdump 实用程序和反汇编代码知道 VTABLE 的地址(即对应的vptr)。vptr 通常存储在 object 的第一个字节中。(更正/编辑这个)。有这个使用虚函数的简单代码:

class base
{
public:
    int x;
    virtual void func()
    {
        //test function

    }

};

class der : public base
{
   void func()
    {
        //test function

    }

};

/*
 * 
 */
int main() {
    int s = 9;
    base b;
    der d ;
    std::cout<<"the address of Vptr is = "<<(&b+0)<<std::endl;
    std::cout<<"the value at Vptr is = "<<(int*)*(int*)((&b+0))<<std::endl;

    return 0;
}

以下是代码的输出:

the address of Vptr is = 0x7fff86a78fe0
the value at Vptr is = **0x400c30**

以下是主要功能的一部分 - 代码的反汇编

base b;
  4009b4:   48 8d 45 d0             lea    -0x30(%rbp),%rax
  4009b8:   48 89 c7                mov    %rax,%rdi
  4009bb:   e8 f4 00 00 00          callq  400ab4 <_ZN4baseC1Ev>
    der d ;
  4009c0:   48 8d 45 c0             lea    -0x40(%rbp),%rax
  4009c4:   48 89 c7                mov    %rax,%rdi
  4009c7:   e8 fe 00 00 00          callq  400aca <_ZN3derC1Ev>

这里显示 _ZN4baseC1Ev 是基础对象的地址,_ZN3derC1Ev 是派生对象的地址。

在 _ZN4baseC1Ev

0000000000400ab4 <_ZN4baseC1Ev>:
  400ab4:   55                      push   %rbp
  400ab5:   48 89 e5                mov    %rsp,%rbp
  400ab8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400abc:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400ac0:   48 c7 00 30 0c 40 00    movq   $0x400c30,(%rax)
  400ac7:   c9                      leaveq 
  400ac8:   c3                      retq   
  400ac9:   90                      nop

    0000000000400aca <_ZN3derC1Ev>:
        }


#include<iostream>
class base
{
public:
    int x;
    virtual void func()
  400a8a:   55                      push   %rbp
  400a8b:   48 89 e5                mov    %rsp,%rbp
  400a8e:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
    {
        //test function

    }
  400a92:   c9                      leaveq 
  400a93:   c3                      retq   

0000000000400a94 <_ZN3der4funcEv>:

};

class der : public base
{
   void func()
  400a94:   55                      push   %rbp
  400a95:   48 89 e5                mov    %rsp,%rbp
  400a98:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
    {
        //test function

    }
  400a9c:   c9                      leaveq 
  400a9d:   c3                      retq   

0000000000400a9e <_ZN4baseC2Ev>:
 */

#include <stdlib.h>
#include<iostream>
class base
{
  400a9e:   55                      push   %rbp
  400a9f:   48 89 e5                mov    %rsp,%rbp
  400aa2:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400aa6:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400aaa:   48 c7 00 50 0c 40 00    movq   $0x400c50,(%rax)
  400ab1:   c9                      leaveq 
  400ab2:   c3                      retq   
  400ab3:   90                      nop

0000000000400ab4 <_ZN4baseC1Ev>:
  400ab4:   55                      push   %rbp
  400ab5:   48 89 e5                mov    %rsp,%rbp
  400ab8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400abc:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400ac0:   48 c7 00 50 0c 40 00    movq   $0x400c50,(%rax)
  400ac7:   c9                      leaveq 
  400ac8:   c3                      retq   
  400ac9:   90                      nop

0000000000400aca <_ZN3derC1Ev>:
    }

};

这是objdump -S exe文件输出的链接

还有 objdump -t virtualfunctionsize | grep vtable 给出了这个:

0000000000400c40  w    O .rodata    0000000000000018              vtable for base
0000000000601e00 g     O .dtors 0000000000000000              .hidden __DTOR_END__
0000000000400b00 g     F .text  0000000000000089              __libc_csu_init
0000000000400c20  w    O .rodata    0000000000000018              vtable for der

我想知道 - VTABLE地址和它所表示的相应虚函数是什么。

  • Vptr 的地址是 = 0x7fff86a78fe0 ,这代表什么 - VTABLE 位置?

  • Vptr 的值是 = 0x400c30 - 这代表什么 - 基类的第一个虚函数?

  • 怎样才能找到派生类的虚函数的后续地址呢?

Rgds,软软的

4

2 回答 2

2

Gcc 遵循这个 C++ ABI:http ://refspecs.linuxbase.org/cxxabi-1.83.html#vtable

要查看gcc生成的vtable,可以用“gcc -S”编译生成汇编源,然后通过c++filt过滤

您可以看到生成了以下 vtable:

    .type   vtable for base, @object
    .size   vtable for base, 24
vtable for base:
    .quad   0
    .quad   typeinfo for base
    .quad   base::func()

您可以看到前两个 8 字节值为零(从顶部偏移,派生类在基类中的偏移量)和指向 typeinfo 的指针。然后真正的 vtable(指向虚函数的指针)开始。这就是您在调试输出中看到的 vptr 值。这解释了 +0x10 偏移量。

于 2012-05-11T11:31:01.220 回答
1

_ZN4baseC1Evbase::base(),基构造函数,_ZN3derC1Ev是派生构造函数。您可以使用诸如c++filt对名称进行解构的工具。它们不是实际对象的地址。

正如预期的那样,基础对象的地址b是在堆栈上。0x7fff86a78fe0对于此编译器,这与 vptr 的地址相同,它是指向虚拟成员的函数指针数组的指针。

如果取消引用它,您将获得指向基类中第一个虚函数 (0x400c30) 的指针的地址。

编辑:您需要再次取消引用它以获取base::func(). 使用类似的东西 (int*)*(int*)*(int*)(&b)

于 2012-05-11T10:25:11.107 回答