什么时候gcc __attribute __((构造函数))运行?
假设我有一个带有GCC构造函数的libA.so。
我的程序“程序”依赖于libA.so,所以当我运行它时,libA.so被打开并且它的构造函数被执行。 现在,我还有一个模块libC.so,它也依赖于libA。 我运行dlopen("libC.so")
, 加载libC,并根据我的实验,也执行libA的构造函数 。
依赖关系看起来像这样:
- libA有构造函数
- libB也有一个构造函数
- libC依赖于libA和libB
- 程序取决于libA
- 程序通过dlopen()链接libC
现在,当我运行程序时:
- libA的构造函数在main()启动之前运行
- libB的构造函数由dlopen()运行
显然,当它们被加载到内存中时,dlopen会执行库的构造函数。 这是在某处指定的,链接器如何检查哪些库已经加载?
(为什么我要问:在一个场合,我有一个构造函数在一些不完全理解的情况下被执行了两次。我是否正确地假设这完全被打破并且在正常情况下不应该发生?)
对于ELF文件, __attribute__((constructor))
标记的函数最终从DT_INIT
(初始化函数)标记运行。 同样,对于__attribute((destructor))
和DT_FINI
(终止函数)标记。
初始化函数在执行重定位之后运行,并且在将控制返回到程序之前运行,对于程序加载时加载的共享对象在将控制转移到main()
之前意味着,并且对于运行时加载的共享对象可能在从返回之前解释为dlopen()
。 DT_NEEDED
共享对象的初始化函数在当前共享对象中的初始化函数之前运行。
在用户atexit()
处理程序之后,终止函数从atexit()
处理程序运行。 终止function以其相应的初始化function的相反顺序运行。
ELF标准注意到以下内容:
动态链接器确保它不会多次执行任何初始化或终止函数。
如果你没有看到,那就是一个bug。