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 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章