所有常用的C++ABI和篡改方案都是什么



gcc/Linux使用的C++ABI/mangling方案称为安腾C++ABI。Mangling是第5.1节。

除此之外,还有多少其他常用的C++ABI和篡改方案?它们叫什么?

(例如,我假设MSVC和Windows都有自己的一个?它叫什么?它有文件记录吗?(

我将尝试总结(非常短的(邮件列表线程,并添加我自己在编译时的一些回忆(大约在2005-2010年使用EDG的前端(:

  • 安腾C++ABI被许多POSIX ish平台使用。存在几种实现(例如GNU有一种,LLVM/Clang有一个(,它们自然会略有不同——这既是因为bug,也是因为它们可能或多或少地关心供应商特定的角落案例。

    • 例如,Clang将(非ISO标准(块类型int (^)(int)修改为U13block_pointerFiiE。Clang和GCC的c++filt都不能往返于类似int (^)(int)的任何东西。GCC根本不支持块类型
  • Microsoft使用Microsoft C++ABI。

  • 最初的Cfront使用了你可以称之为";Cfront C++ABI;ARM的§7.2c中记录。Edison设计集团的Cfront类似前端使用的默认损毁是Cfront C++ABI的直系后裔。

    • 但EDG也支持安腾ABI(至少(作为一种替代方案,可在编译时进行配置(至少(
  • 我相信还有其他的损毁计划存在,尤其是如果你看看20世纪90年代的寒武纪大爆发,不要坚持认为损毁一定一直存活到20世纪20年代。。。

下面是这三种损伤的具体例子:

namespace Hello { class World; }
struct Class {
explicit Class(int);
int func(const double&, Hello::World*) const;
};

安腾损毁:_ZN5ClassC1Ei_ZNK5Class4funcERKdPN5Hello5WorldE

微软芒果:??0Class@@QEAA@H@Z?func@Class@@QEBAHAEBNPEAVWorld@Hello@@@Z

前处理:__ct__5ClassFifunc__5ClassFRCdPQ25Hello5World。(ARM没有解释如何区分完整的对象构造函数和用于虚拟库的子对象构造函数;你必须看看实际的实现,比如EDG,才能弄清楚。(


与名称篡改正交,还有很多ABI决策要做:

  • 异常处理是使用表(正如安腾ABI被指定的那样(,还是围绕每个函数使用setjmp/longjmp序言/尾声代码?

  • vtable是否包含Cfront中使用的、ARM§10.8c中所示的简单函数指针(当需要转换为虚拟基时指向"thunk"(,或更复杂的模式(消除了对"thunk"代码的需要,但使每个虚拟调用站点复杂化(?

  • int (Widget::*)()的尺寸和布局是多少?指向非虚拟函数的指针可以很容易地与int (*)()大小相同,但如果Widget包含虚拟函数呢?安腾ABI表示int (Widget::*)()应该是两个指针大小。如果我理解正确的话,Microsoft ABI也只是简单地使用thunk,而int (Widget::*)()是单个函数指针的大小(可能指向thunk(。

    • 奇怪的是,从指向虚拟基成员的指针转换为指向派生成员的指针很酷的是MSVC,而GCC/Clang拒绝了它。这可能与…有关
  • 虚拟基的结构布局是什么——在类的前面、类的末尾、中间(如ARM§10.5c中所示,尽管可能是偶然的(?它们的偏移量在运行时存储在哪里?——每次我们将未知动态类型的指针投射到它的一个虚拟基时,我们都需要知道这些偏移量。Microsoft ABI既使用";vfptr";(到虚拟函数表(;vbptr";(到虚拟基偏移量表(,而安腾ABI只使用vfptr(他们只是称之为"vptr"(,并且虚拟基偏移存储在vtable之前的内存中。

    • struct E { virtual ~E(); };struct F : virtual E {};-微软生产sizeof(F)==16,而安腾和Cfront只生产8
  • 我们如何实现内联函数和模板:prelinker?COMDAT部分(如果是,我们如何命名它们(?

可能还有更多我没想到的旋钮。

最新更新