GCC 的构造和析构函数
dlopen 打开一个动态链接库时,它会首先调用函数 _init 做一些初始化的操作,结束时执行 _finit 进行收尾操作。但是我们编写动态链接库时候不能覆盖 _init 和 _finit,不过可以利用 GCC 指定构造函数和析构函数函数来完成,示例代码:
#include <stdio.h> __attribute ((constructor)) void init(void) { printf("%s\n", __func__); } __attribute ((destructor)) void fini(void) { printf("%s\n", __func__); } int main(void) { printf("main\n"); return 0; }
执行:
$ ./a.out init main fini
GCC4.7 以前的版本,编译时会将构造函数和析构函数放在 .ctor 段和 .dtor 段中,分别由 __do_global_ctors_aux 和 __do_global_dtors_aux 去执行:
$ objdump -s -j .ctors a.out a.out: file format elf32-i386 Contents of section .ctors: 8049f00 ffffffff 00000000 ........ $ objdump -s -j .dtors a.out a.out: file format elf32-i386 Contents of section .dtors: 8049f08 ffffffff 00000000 ........ $ nm ./a.out | grep '__[C|D]TOR' 08049f04 d __CTOR_END__ 08049f00 d __CTOR_LIST__ 08049f0c D __DTOR_END__ 08049f08 d __DTOR_LIST__
从 GCC4.7 开始,.ctor 和 .dtor 段被移除,构造函数和析构函数分别存放到 .init_array 和 .fini_array 中了。用 4.7 的 GCC 编译后如下:
Contents of section .init_array: 8049f00 d0830408 fc830408 ........ Contents of section .fini_array: 8049f08 b0830408 10840408 ........
段尾的 fc830408 和 10840408 就是构造函数和析构函数的内存地址 0x080483fc 和 0x08048410。