c – 在MSVC ABI中,如何只给出一个(void *)可靠地找到vtable?

c – 在MSVC ABI中,如何只给出一个(void *)可靠地找到vtable?,第1张

概述这个问题具体是关于非便携式MSVC ABI的东西. 我试图在明显不可移植但不是魔法的C中写出相当于C的typeid.对于Itanium ABI(在Linux / Mac上使用),它非常简单: const std::type_info& dynamicast_typeid(void *mdo){ std::type_info **vptr = *reinterpret_cast<std:: 这个问题具体是关于非便携式MSVC ABI的东西.

我试图在明显不可移植但不是魔法的C中写出相当于C的typeID.对于Itanium ABI(在Linux / Mac上使用),它非常简单:

const std::type_info& dynamicast_typeID(voID *mdo){    std::type_info **vptr = *reinterpret_cast<std::type_info ***>(mdo);    std::type_info *typeinfo_ptr = vptr[-1];    return *typeinfo_ptr;}

所以现在我正在看64位的MSVC ABI,然后对它说,我很难过.对于非常简单的类,以偏移0处的vfptr开头的类,它几乎和Itanium一样简单:

const std::type_info& dynamicast_typeID(voID *mdo){    int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];    char *result = (char *) rtti_complete_object_locator;    result -= rtti_complete_object_locator[5];    result += rtti_complete_object_locator[3];    return *(std::type_info*)result;}

(此代码基于the Wine project’s __RTtypeid.)

问题是某些C类不是以偏移0处的vfptr开头的!有时他们从vbptr开始.

struct Class1 { virtual ~Class1() {} };struct Class2 : virtual Class1 {};

Class1以vfptr开头; Class2以vbptr开头.

当一个类以vbptr开头时,我相信它的第一个虚拟基础子对象(它在布局顺序中的第一个,因此它的“最活泼的”)总是会在其偏移0处有一个vfptr.所以如果我知道我’在处理以vbptr开头的类时,我想这样做:

const std::type_info& dynamicast_typeID_for_vbptr_class(voID *mdo){    int first_vbase_offset = ((int**)mdo)[0][1];    mdo = (char*)mdo + first_vbase_offset;    int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];    char *result = (char *) rtti_complete_object_locator;    result -= rtti_complete_object_locator[5];    result += rtti_complete_object_locator[3];    return *(std::type_info*)result;}

我已经确定了MSVC does actually generate相当于

if constexpr(IS_VBPTR_CLASS) {        int first_vbase_offset = ((int**)mdo)[0][1];        mdo = (char*)mdo + first_vbase_offset;    }    return __RTtypeID(mdo);

当编译C表达式typeID(x)时 – 其中IS_VBPTR_CLASS是伪代码,“编译器根据x的静态类型以及编译器知道每种类型的布局这一事实神奇地知道x是否具有vbptr.”

但是,在我的情况下,我不知道x的静态类型,即使我这样做,我也不知道如何找出(从C中,使用模板元编程)x是否以vbptr开头.

最后,我继续前进并稍微捏了一下

const std::type_info& dynamicast_typeID(voID *mdo){    while (((int**)mdo)[0][0] == 0) {        mdo = (char *)mdo + ((int**)mdo)[0][1];    }    int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];    char *result = (char *)complete_object_locator;    result -= rtti_complete_object_locator[5];    result += rtti_complete_object_locator[3];    return *(std::type_info*)result;}

只发现存储在vftable中的“Class1中的Class1”的typeinfo保存了子对象类型Class1的typeinfo,而不是最派生类型的Class2!所以还有另一块拼图丢失了.

所以我的问题简而言之:给定(voID *)& object_of_type_class2,如何检索typeID(Class2)?

解决方法 我有一些现在有用的东西!

函数dynamicast_to_mdo相当于dynamic_cast< voID *>(p) – 它调整p以指向其最派生的对象.

函数dynamicast_typeID相当于typeID(p) – 它从p的vtable中获取typeinfo.我只是在使用我在问题中给出的软糖/黑客,我实际上不确定为什么我几个小时前得到了错误的答案;我想当我看到错误的typeinfo时,可能是因为我不小心试图将悬挂引用的typeID取为已销毁的堆栈变量.

// 64-bit MSVC ABIvoID *dynamicast_to_mdo(voID *p){    if (((int**)p)[0][0] == 0) {        p = (char *)p + ((int**)p)[0][1];    }    int *complete_object_locator = ((int ***)p)[0][-1];    int mdoffset = complete_object_locator[1];    voID *adjusted_this = static_cast<char *>(p) - mdoffset;    return adjusted_this;}// 64-bit MSVC ABIconst std::type_info& dynamicast_typeID(voID *p){    if (((int**)p)[0][0] == 0) {        p = (char *)p + ((int**)p)[0][1];    }    int *complete_object_locator = ((int ***)p)[0][-1];    char *result = (char *)complete_object_locator;    result -= complete_object_locator[5];    result += complete_object_locator[3];    return *(const std::type_info*)result;}
总结

以上是内存溢出为你收集整理的c – 在MSVC ABI中,如何只给出一个(void *)可靠地找到vtable?全部内容,希望文章能够帮你解决c – 在MSVC ABI中,如何只给出一个(void *)可靠地找到vtable?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1225091.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存