C++复杂类型-对象及虚函数表在可执行文件的存放位置与初始化时机

C++复杂类型-对象及虚函数表在可执行文件的存放位置与初始化时机

 

使用objdump -D -C反汇编-D会输出所有段,-C可以看到代码中的变量名

 

rodata 只读数据段

 

 

可看到只读数据段中有虚函数表(虚函数表的第一个4字节是空的,第二个4字节存放是typeinfo的地址,第三个4字节存放的是Test类的虚函数fun的地址),和用于RTTI的Test类的类型信息

类成员变量const Test::c ,static const Test::d=1,全局const Test e(3),全局static const Test f(4),main函数局部变量static const Test f(8); 并未出现在只读数据段

 

data段

 

可读写数据段只存放了类成员变量static Test::b

 

 

bss段

 

 

bss段存放了全局对象Test g(5),全局对象const Test e(3),全局对象static const Test f(4)及Test h=Test(6),main函数中的局部变量static Test j(7),static const Test k(8),static Test m=Test(10),可看到,全局对象,static修饰的局部对象无论有没有被初始化都被安排在了bss段

此外还多了三个变量

 

 

text段

 

 

main函数的c++代码只有3行但是却有40多行的反汇编代码,奇怪吧

实例化局部对象Test h(6)

第一二三行代码为Test构造函数准备参数和this指针,由第二行代码可知Test h(6)是存在于栈中的,第四行代码调用Test构造函数,生成对象Test h(6);

 

实例化对象static Test j(7)

在实例化static修饰的对象时,比普通局部对象多出的这些代码是编译器插入了初始化状态及锁用于保证static对象在多线程环境下也只被初始化一次,

这一长串代码的大概意思就是,在初始化static对象前,先判断对象是否已初化过,如已初始化过则跳过这段代码,如未初如始化则获取锁,进行初始化并设置已初始化标识,DCL啊

 

第一行mov    $0x804a0b0,%eax

804a0b0是bss段的一个地址,这个地址存放的对象包含一个变量用来存放标识static Test j(7)对象是否已经被初始化过,和一个锁对象用于多线程环境下防止多线程并发初化导致static变量被多次初始化

 

 

第6行call   80484b0 <__cxa_guard_acquire@plt>获取锁与第15行call   8048500 <__cxa_guard_release@plt>释放锁之间的代码用于实例化对象,设定是否初始化标识,在多线程环境中也可保证变量只被初始化一次

 

至此我们看到了局部对象,static修饰的局部对象是在何处初始化的,那么全局对象?

 

在反汇编代码中找到了如下代码,全局对象正是在这里初始化的,这段代码会在main函数调用前先被调用

 

好像忘了对象的虚函数表指针的初始化了

如下代码

反汇编如下

从反汇编代码可以看到虚函数表指针是在构造函数中初始化的

 

总结一下:

全局对象,static,static const修饰的对象会存放在bss段

对于static,static const修饰的局部变量是在函数内进行初始化,而且在多线程环境下也只会被初始化一次

对于全局对象是在main函数执行前进行初始化

局部的,const 修饰的对象会存放在栈中,在函数运行时初始化

对于new出来的对象不用多说当然是在heap了,在operator new分配到内存后,再调用构造函数进行初始化类的

类的static成员变量是存放在data段,并且不计入对象的size

虚函数表及类的类型信息存放在rodata段

类的static const对象并未出现在可执行文件中,编译器对其直接进行了值替换

 

 

为什么对象不能被存放在data段?

 

注:gcc version 4.8.4 

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页