为什么GCC将对全局实例的构造函数的调用放入不同的部分(取决于目标)?

Ber*_*ium 7 c++ microcontroller gcc ld linker-scripts

我有一些非空构造函数的全局实例的简单声明.这些构造函数在启动期间自动调用.我在Linux上交叉编译C++到不同的微控制器目标.


至于

  • 臂无 - EABI-GCC-4.8.4
  • rx-elf-gcc-4.8-GNURX_v14.03(GCC 4.8.3)

对构造函数的调用将放入该.init_array部分.地图文件如下所示:

.init_array 0x00007cb8 0x4 libmotor.o

.init_array 0x00007cbc 0x4 libaudio.o


至于

  • MIPS-ELF-GCC-4.8.2
  • AVR-GCC-4.8.1
  • MSP430-GCC-4.6.3

这些调用进入该.ctors部分:

.ctors 0x000000009d011508 0x4 libmotor.o

.ctors 0x000000009d01150c 0x4 libaudio.o


编译完成后-ffunction-sections -fdata-sections,链接器得到了--gc-sections.

所有二进制文件都可以工作,但我想将所有调用放在同一部分(以简化链接器脚本的维护).

  • 为什么有不同的目标部分?
  • 是否可以使用命令行选项更改默认部分?
  • 如果命令行选项没有退出:是否可以在GCC编译时定义默认部分?

Ber*_*ium 7

Bug 46770 - 在支持它们的目标上用 .init_array/.fini_array 替换 .ctors/.dtors 中有很长的讨论

我提取了一些说明情况的项目:

为什么.init_array出现了?

  • 我们添加了.init_array/.fini_array以便将.init包含实际代码的 SVR4 版本与包含函数指针并使用DT_INIT_SZ动态数组中的条目而不是由 crt*.o 文件贡献的序言和结尾部分的 HP-UX 版本混合。HP-UX 版本被视为一种改进,但它不兼容,因此我们重命名了部分和动态表条目,以便两个版本可以并行运行,并且实现可以从一个缓慢过渡到另一个.

  • 在 HP-UX 上,我们将.init/.init_array用于静态构造函数,并且他们将相应的静态析构函数注册在一个特殊atexit列表中,而不是将析构函数添加到.fini_array,以便我们可以dlclose()正确处理事件上的析构函数(取决于您对“正确”的解释)语境)

执行顺序之间不同.ctors.init_array

.ctors节的倒序

某些程序可能隐含地依赖于稍后链接的档案中的全局构造函数在针对这些档案链接的对象中的构造函数之前运行的事实。也就是说,给定

g++ foo.o -lbar
Run Code Online (Sandbox Code Playgroud)

其中 bar 是静态存档,而不是共享库,那么当前从 libbar.c 中拉入的对象中的全局构造函数将在 foo.o 中的全局构造函数之前执行。这是一个有意的选择,因为它更可能是正确的而不是相反的。但是,C++ 标准不保证它,因此任何依赖此顺序的程序在技术上都是无效的。

倒序的问题 .ctors

在 GNU 中完成了大量工作ld并将gold构造函数从 移动.ctors.init_array,所有这些都是为了改善 Firefox 的启动延迟

使用.init_array/.fini_array而不是.ctors/.dtors消除了对关联(相对)重定位的需要,并避免了启动时的向后磁盘搜索(因为 while.ctors是向后处理的,所以.init_array是向前处理)。

过渡.ctors.init_array

GNUldgold现在的主线版本都将.ctors节放入.init_array节中,并将.dtors节放入.fini_array节中。

评论:可能是在 GCC 4.7 中引入的。

手臂

ARM EABI.init_array从第一天起就一直在使用。

评论:尽管如此,默认链接描述文件包含一个.ctors输出部分。

海湾合作委员会配置

您拥有的一种选择是使用 --disable-initfini-array 配置 gcc。

评论:此选项不会出现在mips-elf-gcc -v(-v显示 "Configured with: ...")的输出中。