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



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


对于

  • 臂-酮-eabi-gcc-4.8.4
  • rx-elf-gcc-4.8-GNURX_v14.03(通用条款4.8.3)

对构造函数的调用被放入CCD_ 1部分。地图文件如下所示:

.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部分:

.cctors 0x000000009d011508 0x4 libmotor.o

.ctors 0x000000009d01150c 0x4 libaudio.o


-ffunction-sections -fdata-sections进行编译,得到--gc-sections

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

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

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

我提取了一些项目来解释这种情况:

为什么会出现.init_array

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

  • 在HP-UX上,我们使用.init_array0/.init_array作为静态构造函数,它们在一个特殊的atexit列表中注册了相应的静态析构函数,而不是将析构函数添加到.fini_array中,这样我们就可以正确地处理dlclose()事件上的析构函数(根据您在该上下文中对"正确"的解释)

.ctors.init_array的执行顺序不同

.ctors段回水顺序

一些项目可能隐含地依赖于这样一个事实:稍后链接的存档中的构造函数在链接到这些档案的对象。也就是说,给定

g++ foo.o -lbar

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

.ctors的退单问题

GNU ldgold都做了大量工作,将构造函数从.ctors移动到.init_array,所有这些都是为了改善Firefox 的启动延迟

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

.ctors.init_array的转换

GNU ldgold的主线版本现在将.ctors节放入.init_array节,将.dtors节放入.fini_array节。

评论:可能与GCC 4.7一起引入。

ARM

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

注释:尽管如此,默认的链接器脚本包含一个.ctors输出部分。

GCC配置

您可以选择使用--disable initfini数组配置gcc。

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

最新更新