【问题标题】:When exactly is gcc __attribute__((constructor)) run?gcc __attribute__((constructor)) 到底什么时候运行?
【发布时间】:2014-01-28 04:30:32
【问题描述】:

假设我有一个带有 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 在将库加载到内存时执行它们的构造函数。这是在某处指定的吗?链接器如何检查哪些库已经加载?

(为什么我要问:在某些情况下,我在某些未完全理解的情况下执行了两次构造函数。我是否可以假设这完全被破坏并且在正常情况下不应该发生?)

【问题讨论】:

  • 嗯,这是著名的未指定/未指定。您多久可以加载一次库?你能卸载一个库吗?共享库上的两个独立依赖项是独立的还是相同的?问题大于问题。
  • 贴出你的代码sn-ps,有点难以理解你想在这里解释什么。
  • 模块构造函数只被调用一次,除非你手动卸载模块,这不太可能。
  • 您使用哪个平台观察到这种行为?
  • 这里似乎有问题:“我还有一个模块 libB.so,它也依赖于 libA。我运行 dlopen("libA.so"),它加载libB, ..."

标签: c gcc shared-libraries posix dlopen


【解决方案1】:

对于 ELF 文件,__attribute__((constructor)) 标记的函数最终从 DT_INIT(初始化函数)标签运行。 __attribute((destructor))DT_FINI(终止函数)标签也是如此。

初始化函数在执行重定位之后运行,在将控制权返回给程序之前,这对于程序加载时加载的共享对象意味着在将控制权转移到main()之前,对于运行时加载的共享对象可能被解释为在从dlopen() 返回之前。 DT_NEEDED共享对象的初始化函数在当前共享对象的初始化函数之前运行。

终止函数从atexit() 处理程序运行,在用户atexit() 处理程序之后。终止函数的运行顺序与其相应的初始化函数相反。

ELF 标准指出以下几点:

动态链接器确保它不会 多次执行任何初始化或终止函数。

如果你看到的不是这样,那就是一个错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 2016-12-03
    • 2023-03-31
    相关资源
    最近更新 更多