没有链接具有构造函数属性的gcc函数

时间:2011-07-05 22:56:35

标签: gcc attributes constructor static-linking

我有一堆静态库,它们是相互依赖的。 由于依赖性,我在为目标链接这些库时遇到了问题。 作为一种解决方法,我从所有库中创建了一个归档文件。

其中一个静态库具有构造函数和析构函数,因此组合归档(使用 nm objdump 检查归档) 但是当我使用组合存档作为目标时,最终的二进制文件不包含构造函数和析构函数。

我也试过--whole-archive但是这个选项对我来说似乎不起作用(二进制大小没有增加)。

任何可能出错的想法。 谢谢

2 个答案:

答案 0 :(得分:7)

链接器只加载它必须的模块(即实际引用隐式显式),除非你强制它。

这两个都是好事,而且不幸。它使链接过程更快,并防止代码膨胀。它通常也不会引起问题,因为通常你会以某种方式引用所需的所有模块,而不需要你不引用的模块。通常情况下,
但它也是导致此静默失败的原因:链接器从不加载包含构造函数/析构函数的模块,从不查看它。那是因为你实际上从未调用过这些函数。

您可以通过显式链接与包含构造函数/析构函数的源对应的目标文件来强制链接器包含该模块。

换句话说,如果构造函数/析构函数在foo.c中,则将-l/path/to/foo.o添加到链接器的选项中,或者只是将命令行上的foo.o传递给链接器(作为额外的参数)。

在任何一种情况下,通过这样做,你明确地告诉链接器考虑这个模块,这样做会使它找到构造函数并正确调用它们。

另一种选择(不需要你使用命令行)可能会将一个变量或一个函数(不一定做任何事情)放入与构造函数/析构函数相同的源文件中并从任何函数中调用它主程序中的源文件 这也将强制链接器加载包含模块(它将在哪里找到构造函数)。

<强>更新
我测试了那个替代方案,它工作正常:

/* libcode.c */
void enable_constructors() { /* do nothing */ }
void __attribute__ ((constructor)) con() { __builtin_puts("construct"); }
void __attribute__ ((destructor))  des() { __builtin_puts("destruct"); }


/* main.c */
extern void enable_constructors();

int main()
{
    enable_constructors();
    __builtin_puts("main");
    return 0;
}

输出是:

construct
main
destruct

它也适用于您从主程序中的源文件触摸的全局变量:

/* libcode.c */
int enable_constructors; /* not used for anything */

void __attribute__ ((constructor)) cons() { __builtin_puts("construct"); }
void __attribute__ ((destructor)) des() { __builtin_puts("destruct"); }


/* main.c */
extern int enable_constructors;

int main()
{
    ++enable_constructors; /* touch the other module */
    __builtin_puts("main");
    return 0;
}

答案 1 :(得分:0)

从另一个答案开始:

  

您可以通过显式链接与包含构造函数/析构函数的源代码相对应的目标文件来强制链接程序包括该模块。

使用现代CMake,这就像库中的INTERFACE源一样容易。只需使用专用的源文件作为构造函数即可。

cmake_minimum_required(VERSION 3.13)

add_library(mylib STATIC libsource.c)
target_sources(mylib INTERFACE lib_ctor.c)
# CMake prior 3.13 requires an absolute path
# target_sources(mylib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lib_ctor.c)

add_executable(prog app.c)
target_link_libraries(prog mylib)

在这里,lib_ctor.c将包含构造函数。将INTERFACE源添加到与mylib链接的每个目标的源文件列表中。因此它们被明确链接,并且链接器读取了构造函数。

我在--whole-archive和其他黑客上浪费了一两个小时,然后才意识到我的构建系统可以以一种更加简洁的方式来解决这个问题。由于CMake在当今非常流行,并且这是“ gcc强制构造函数”和“ gcc构造函数未链接”之类的术语的热门搜索结果,我想与大家分享。