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;
}

执行:

[lu4nx@localhost tmp]$ ./a.out
init
main
fini

GCC4.7 以前的版本,编译时会将构造函数和析构函数放在 .ctor 段和 .dtor 段中,分别由 __do_global_ctors_aux 和 __do_global_dtors_aux 去执行:

[lu4nx@localhost tmp]$ objdump -s -j .ctors a.out

a.out:     file format elf32-i386

Contents of section .ctors:
 8049f00 ffffffff 00000000                    ........
[lu4nx@localhost tmp]$ objdump -s -j .dtors a.out

a.out:     file format elf32-i386

Contents of section .dtors:
 8049f08 ffffffff 00000000                    ........
[lu4nx@localhost tmp]$ 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。