GCC的__attribute__ ((constructor))和__attribute__ ((destructor))


    通過一個簡單的例子介紹一下gcc的__attribute__ ((constructor))屬性的作用。gcc允許為函數設置__attribute__ ((constructor))和__attribute__ ((destructor))兩種屬性,顧名思義,就是將被修飾的函數作為構造函數或析構函數。程序員可以通過類似下面的方式為函數設置這些屬性:  

void funcBeforeMain() __attribute__ ((constructor)); 

void funcAfterMain() __attribute__ ((destructor));

也可以放在函數名之前:
void __attribute__ ((constructor)) funcBeforeMain();
void __attribute__ ((destructor)) funcAfterMain();
帶有(constructor)屬性的函數將在main()函數之前被執行,而帶有(destructor)屬性的函數將在main()退出時執行。
下面給出一個簡單的例子:
 1 #include <stdio.h>
 2 
 3 void __attribute__((constructor)) funcBeforeMain()
 4 {
 5     printf("%s...\n", __FUNCTION__);
 6 }
 7 
 8 void __attribute__((destructor)) funcAfterMain()
 9 {
10     printf("%s...\n", __FUNCTION__);
11 }
12 
13 int main()
14 {
15     printf("main...\n");
16     return 0;
17 }
View Code

運行結果:

funcBeforeMain...
main...
funcAfterMain...

  為什么有這么神奇的函數呢?它是怎么實現的呢?

  通過翻看GNU的link文檔,我找到了答案:

在GNU link中,也就是你的系統中的XX.S文件,找到了詳細的答案,

當使用a.out文件來鏈接程序時,鏈接器使用一個與眾不同的關鍵字construct 來支持C++里面的全局constructors 和 destructors,當鏈接對象不支持任意剖分時,鏈接器可以通過名字來自動識別構造器和解析器。

link文件中的構造器格式如下:

 1       __CTOR_LIST__ = .;
 2       LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
 3       *(.ctors)
 4       LONG(0)
 5       __CTOR_END__ = .;
 6       __DTOR_LIST__ = .;
 7       LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
 8       *(.dtors)
 9       LONG(0)
10       __DTOR_END__ = .;
View Code

符號__CTOR_LIST__標志者全局構造器的開始,符號__DTOR_LIST標志着構造器的結束。列表中的第一個關鍵字代表條目的個數,后面緊跟者是構造器和解析器的地址。最后是一個零字符。編譯器必須排隊去執行這些代碼。

GNU編譯器通常通過一個子程序__main函數前面調用constructor,__main在被調用時會自動的插入到main函數的起始代碼中。同樣的是,GNU通過運行atexit來調用destructors,或者是通過函數exit來直接調用。

 

參考文檔:

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM