是首先调用 init 部分函数还是构造函数?

Is the init section functions called first or the constructor functions?

考虑以下代码:

#include <iostream>
#include <stdio.h>

void preinit_void();
void init_void();

__attribute__((section(".init_array")))
    void (*p_init)(void) = &init_void;

void constructor_void() __attribute__((constructor));
void constructor_void() {
    printf(__FUNCTION__);
}

__attribute__((section(".preinit_array")))
    void (*p_preinit)(void) = &preinit_void;


void preinit_void() {
    printf(__FUNCTION__);
}

void init_void() {
    printf(__FUNCTION__);
}

int main() {
    std::cout << __FUNCTION__ << '\n';
}

在 运行 上输出的代码是

preinit_voidinit_voidconstructor_voidmain

如果我将代码更改为:

#include <iostream>
#include <stdio.h>

void preinit_void();
void init_void();

void constructor_void() __attribute__((constructor));
void constructor_void() {
    printf(__FUNCTION__);
}

__attribute__((section(".init_array")))
    void (*p_init)(void) = &init_void;

__attribute__((section(".preinit_array")))
    void (*p_preinit)(void) = &preinit_void;


void preinit_void() {
    printf(__FUNCTION__);
}

void init_void() {
    printf(__FUNCTION__);
}

int main() {
    std::cout << __FUNCTION__ << '\n';
}

输出变为:

preinit_voidconstructor_voidinit_voidmain

我不清楚哪个部分先初始化。输出的变化仅仅是由于编译器的解析(它首先找到 .init_array 部分而不是 constructor 部分)还是有适当的初始化顺序?

在当前 (GNU) 系统上,对 ELF 构造函数的引用被放置在 .init_array 部分,就像您手动添加的条目一样。这就是为什么在您更改源代码顺序时执行顺序会发生变化的原因。 GCC 和 binutils 具有基于优先级使用单独部分的语言扩展,link 编辑器会将所有内容序列化为每个 application/shared 对象的最终 .init_array 部分(基于源代码和 link顺序,按优先级排序后)。

不同共享对象的构造函数数组是根据对象之间的依赖关系(通过DT_NEEDED标签表示)进行拓扑排序后执行的,因此对象在依赖关系之后被初始化。

这远远超出了 C++ 对初始化的要求,但在各种 (GNU) ABI 相关文档中或多或少地指定了它,并且不会更改。由于引入了新功能(例如,多个 DF_1_INITFIRST 对象,尽管这个有点令人费解),某些方面可能会发生变化,但希望它们只会影响实际使用这些功能的进程。