0 引言

如果没有阅读该系列的第一篇文章,那么需要你先去了解一下,其链接如下深入理解C++对象模型(开始)--由virtual继承说起

本篇是上一篇的续,继续上一篇的例子来引入 深入理解C++对象模型 相关的知识,本篇过后,便会继续回到
深度探索C++对象模型
该书的第三章中来,沿着该章中的相应小节去看看目前gcc编译器是如何model相应的C++对象模型的。

此后,也会讲解该书第4章,第5章以及6,7相关部分内容。

为了阅读本文方便,我将上一篇中的疑问,复制如下

  • 什么是VTT?为什么gcc编译器会针对棱形继承生成VTT?
  • 什么是base object constructor和 complete object constructor
  • 类A的内存模型是怎样的?
  • 类A的构造过程是怎样的?

本文不会详细讲解A的构造过程,如果可能会在后续过程中讲解。

在进行本文之前,需要先明确一下ABI以及C++ABI的相关概念。

1 ABI/C++ ABI

关于ABI的概念,可参考wiki中给出的如下定义

In computer software, an application binary interface (ABI) is an interface between two binary program modules. Often, one of these modules is a library or operating system facility, and the other is a program that is being run by a user.
An ABI defines how data structures or computational routines are accessed in machine code, which is a low-level, hardware-dependent format. In contrast, an API defines this access in source code, which is a relatively high-level, hardware-independent, often human-readable format.

一个ABI是两个二进制模块之间的接口,譬如一个模块是library或者OS,另一个模块是用户程序。 ABI定义了 机器码层面的数据结构表示方式和计算路径,这是一个低层次,硬件相关的格式。

一个ABI主要规定了如下相关细节:

a processor instruction set (with details like register file structure, stack organization, memory access types, ...)
the sizes, layouts, and alignments of basic data types that the processor can directly access
the calling convention, which controls how the arguments of functions are passed, and return values retrieved. For example, it controls:
whether all parameters are passed on the stack, or some are passed in registers;
which registers are used for which function parameters;
and whether the first function parameter passed on the stack is pushed first or last.
how an application should make system calls to the operating system, and if the ABI specifies direct system calls rather than procedure calls to system call stubs, the system call numbers.
and in the case of a complete operating system ABI, the binary format of object files, program libraries, and so on.

故C++ABI所规定的内容也浅而易见:C++对象内存布局,变量命名,函数调用约定以及异常处理等内容。

由此也能得出如下一个结论:

深度探索C++对象模型 这本书实质上是对C++ABI的一个解释和说明; 同理本专题也是针对C++ABI相关内容进一步说明和解释。

在了解ABI/C++ABI相关概念后,便可以继续回答上一篇文章所留疑问。

2 VTT(Table of virtual table)概念

**VTT是Itanium C++ ABI中的概念,现在的gcc/clang编译器均遵循改工业级的C++ABI。
**

**从定义上来说:VTT是指虚表的表(table of virtual table).
**

**从使用角度来说:VTT只有当某个类A拥有虚基类时才会存在,VTT主要作为一种辅助结构用在类A的构造和析构过程中。
**

上述概念也解释了gcc为什么针对棱形继承会生成VTT的原因。此处为了学习方便,贴上上篇文章中的示例代码

class X {};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y, public Z {};

gcc会针对类A,Y,Z生成相应的VTT。 本文通过Compiler Explorer 截取gcc针对类A生成的VTT,其内容如下

VTT for A:
        .quad   vtable for A+24
        .quad   construction vtable for Y-in-A+24
        .quad   construction vtable for Z-in-A+24
        .quad   vtable for A+48
construction vtable for Y-in-A:
        .quad   0
        .quad   0
        .quad   typeinfo for Y
construction vtable for Z-in-A:
        .quad   -8
        .quad   0
        .quad   typeinfo for Z 

关于上述 construction vtable for Y-in-A所代表的含义,此处不详细赘述!

3 base object constructor和 complete object constructor

base object constructor和 complete object constructor 均是由C++ABI所定义,主要是处理virtual base class存在的场景。

base object constructor的定义可参考如下:

The base object constructor is responsible for constructing all of the object’s non-virtual base subobjects (and its member subobjects, and setting its vptr to point to its vtable; and running whatever code is inside the curly braces in your C++ code).

简单来说,base object constructor主要用来构造所有非虚基类子对象。

complete object constructor 的定义可参考如下:

The complete object constructor, which is called whenever you create a complete C++ object, is responsible for constructing all of the most derived object’s virtual base subobjects and then doing all the rest of that stuff too.

简单来说,complete object constructor主要用来构造派生类的所有virtual base 子对象,并完成对象的最终构造。

通过Compiler Explorer 可知,针对类A,gcc编译器生成两个base object constructor 和一个 complete object constructor.

4 A的内存模型

对于A的内存模型,由上一篇文章中gdb感知部分可知,其成员变量布局如下

image.png

通过Compiler Explorer 可知 类A的vtable的内容如下所示

vtable for A:
        .quad   0
        .quad   0
        .quad   typeinfo for A
        .quad   -8
        .quad   -8
        .quad   typeinfo for A 

故综上,我们可以得出A的拥有vtable的最终内存模型如下

image.png

因此,我们可以得出如下结论:

针对多继承,目前gcc也只会生成一个vtable, 而不是 深度探索C++对象模型中 所说的会有多个分离的vtable!

在gcc中,这个vtable叫做 group of vtable!

5 类A的构造过程

关于类A的构造过程本文仅粗略提及,关于详细讲解会留在单独文章说明!

通过Compiler Explorer 可知,在main函数中有如下语句

        lea     rax, [rbp-16]
        mov     rdi, rax
        call    A::A() [complete object constructor] 

上述会调用A::A() [complete object constructor] 也即A的complete object constructor。改函数有如下实现

        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     edx, OFFSET FLAT:VTT for A+8 // 赋值VTT
        mov     rsi, rdx
        mov     rdi, rax
        call    Y::Y() [base object constructor] // 调用相应的base object constructor
        mov     rax, QWORD PTR [rbp-8]
        add     rax, 8
        mov     edx, OFFSET FLAT:VTT for A+16
        mov     rsi, rdx
        mov     rdi, rax
        call    Z::Z() [base object constructor]
        mov     edx, OFFSET FLAT:vtable for A+24
        mov     rax, QWORD PTR [rbp-8]
        mov     QWORD PTR [rax], rdx
        mov     edx, OFFSET FLAT:vtable for A+48
        mov     rax, QWORD PTR [rbp-8]
        mov     QWORD PTR [rax+8], rdx

通过上述实现可知,类A的complete object constructor函数,会先赋值VTT的地址到相应的基类,并调用相应基类的base object constructor,最后返回构造virtual base class。

6 总结

通过本文和上一篇文章,由深度探索C++对象模型的第三章的简单例子说起的故事,便可以初步结束;通过该故事,我们可以了解到

  1. 深度探索C++对象模型 针对目前的gcc/clang编译器实现的C++内存模型有一定的过时
  2. 深度探索C++对象模型中关于多继承以及虚拟继承虚表的内容等也需要更新

有了这两篇文章的引导,我们便可以正式走进深入理解C++对象系列 专题,下一篇 会由 深度探索C++对象模型的第三章的 data member小节说起。

参考:

https://en.wikipedia.org/wiki...

https://refspecs.linuxfoundat...

What is the virtual table table?


秦仁
1 声望2 粉丝