Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ vtables和这个指针_C++_Gcc_This_Vtable_Abi - Fatal编程技术网

C++ vtables和这个指针

C++ vtables和这个指针,c++,gcc,this,vtable,abi,C++,Gcc,This,Vtable,Abi,我试图进一步了解vtable和vpointer的内部工作原理,因此我决定尝试使用一些技巧直接访问vtable。我创建了两个类,Base和Derv,每个类都有两个virtual函数(Derv覆盖Base的函数) 当以这种方式调用其中一个MemberFunction时,例如,call(newbase(1,2),0)调用Base::foo(),很难预测会发生什么,因为调用它们时没有this-指针。我通过添加一个小的模板化函数解决了这个问题,因为我知道g++将this-指针存储在ecx寄存器中(但是这迫

我试图进一步了解vtable和vpointer的内部工作原理,因此我决定尝试使用一些技巧直接访问vtable。我创建了两个类,
Base
Derv
,每个类都有两个
virtual
函数(
Derv
覆盖
Base
的函数)

当以这种方式调用其中一个MemberFunction时,例如,
call(newbase(1,2),0)
调用Base::foo(),很难预测会发生什么,因为调用它们时没有
this
-指针。我通过添加一个小的模板化函数解决了这个问题,因为我知道g++将
this
-指针存储在
ecx
寄存器中(但是这迫使我使用
-m32
编译器标志进行编译):

我决定与大家分享这一点,因为在编写这个小程序的过程中,我对vtables的工作原理有了更多的了解,它可能会帮助其他人更好地理解这些材料。 但是我还有一些问题:
1.编译64位二进制文件时,使用哪个寄存器(gcc 4.x)存储此指针?我尝试了此处记录的所有64位寄存器:

2.何时/如何设置此指针?我怀疑编译器在通过对象的每个函数调用上设置this指针的方式与我刚才的方式类似。多态性实际上就是这样工作的吗?(通过首先设置这个指针,然后调用VTABLE中的虚拟函数)./P>> P > Linux X8664,并且我相信其他UNIX类OSES,函数调用遵循,它本身遵循C++。根据方法的类型,
this
指针可以通过第一个参数隐式传递,也可以通过第二个参数隐式传递(当返回值具有非平凡的复制构造函数或析构函数时,它必须作为堆栈上的临时变量,并且第一个参数隐式是指向该空间的指针);否则,虚拟方法调用与C中的函数调用相同(整数/指针参数在
%rdi
%rsi
%rdx
%rcx
%r8
%r9
,溢出到堆栈;整数/指针在
%rax
中返回;浮动在
%xmm0
-
%xm7
;等等)。虚拟方法分派的工作原理是在vtable中查找指针,然后像调用非虚拟方法一样调用它


<> P>我不太熟悉Windows X64约定,但我相信它与C++方法调用遵循的是与C函数调用(使用不同于Linux的寄存器)完全相同的结构,只是用隐式<代码> < < /C> >参数。你能把它浓缩成核心问题吗?(事实上,你的帖子是否与结尾的问题直接相关?@Oli Charlesworth对我来说是这样的,因为我就是这样回答这些问题的。第二个问题是编译器是否使用类似的方法来启用多态性,因此我认为应该包括我自己的方法。你能推荐另一种媒介,让我分享这些信息并提出问题吗?你应该在这里提出问题,有足够的上下文让它们有意义(听起来你不需要任何上下文来回答这些特定的问题)。如果你想分享你发现的东西,你应该建立一个博客……试试这个——对于微软兼容的C++实现,VDIT在DON Box的基本COM和(我听说COM里面的另一本书)的介绍部分中被解释了。
class Base
{
    int x;
    int y;

    public:
        Base(int x_, int y_) : x(x_), y(y_) {}

        virtual void foo() { cout << "Base::foo(): x = " << x << '\n'; }    
        virtual void bar() { cout << "Base::bar(): y = " << y << '\n'; }
};

class Derv: public Base
{
    int x;
    int y;

    public:
        Derv(int x_, int y_) : Base(x_, y_), x(x_), y(y_) {}

        virtual void foo() { cout << "Derived::foo(): x = " << x << '\n'; }
        virtual void bar() { cout << "Derived::bar(): y = " << y << '\n'; }
};
template <typename T>
void call(T *ptr, size_t num)
{
    typedef void (*FunPtr)();

    size_t *vptr = *reinterpret_cast<size_t**>(ptr);
    FunPtr fun = reinterpret_cast<FunPtr>(vptr[num]);

    //setThisPtr(ptr);      added later, see below!
    fun();
}
template <typename T>
void setThisPtr(T *ptr)
{  
    asm ( mov %0, %%ecx;" :: "r" (ptr) );
}
int main()
{
    Base* base = new Base(1, 2);
    Base* derv =  new Derv(3, 4);

    call(base, 0); // "Base::foo(): x = 1" 
    call(base, 1); // "Base::bar(): y = 2"
    call(derv, 0); // "Derv::foo(): x = 3"
    call(derv, 1); // "Derv::bar(): y = 4"
}