在我的共享库中,我必须在加载时进行某些初始化。如果我使用 GCC 属性
__attribute__ ((constructor))
定义该函数,它将不起作用,即加载链接我的共享库的程序时不会调用它。
如果我将函数名称更改为
_init()
,它就可以工作。显然现在不推荐使用
_init()
和_fini()
函数。
知道为什么
__attribute__ ((constructor))
不起作用吗?这是Linux 2.6.9,gcc
版本3.4.6
编辑:
例如,假设库代码如下:
#include <stdio.h>
int smlib_count;
void __attribute__ ((constructor)) setup(void) {
smlib_count = 100;
printf("smlib_count starting at %d\n", smlib_count);
}
void smlib_count_incr() {
smlib_count++;
smlib_count++;
}
int smlib_count_get() {
return smlib_count;
}
为了构建 .so,我执行以下操作:
gcc -fPIC -c smlib.c
ld -shared -soname libsmlib.so.1 -o libsmlib.so.1.0 -lc smlib.o
ldconfig -v -n .
ln -sf libsmlib.so.1 libsmlib.so
由于 .so 不在标准位置之一,我更新
LD_LIBRARY_PATH
并从另一个程序链接 .so。构造函数不会被调用。如果我将其更改为_init()
,它就可以工作。
好的,所以我已经查看了这个,看起来发生的情况是您的中间
gcc
步骤(使用 -c
)导致了问题。这是我对我所看到的的解释。
当您使用
.o
编译为 setup()
时,gcc
只是将其视为普通函数(因为您不是作为 .so
进行编译,所以它并不关心)。然后,ld
在 ELF 的动态部分中看不到任何 _init()
或类似 DT_INIT
的内容,并假设没有构造函数。
当您使用
.o
编译为 _init()
时,gcc
也会将其视为普通函数。事实上,在我看来,除了函数本身的名称之外,目标文件是相同的!因此,ld
再次查看.o
文件,但这一次看到了一个_init()
函数,它知道它正在寻找该函数,并确定它是一个构造函数,并相应地在新的中创建一个
DT_INIT
条目.so
。最后,如果你一步完成编译和链接,就像这样:
gcc -Wall -shared -fPIC -o libsmlib.so smlib.c
然后发生的事情是,
gcc
在创建共享对象的上下文中看到并理解
__attribute__ ((constructor))
,并相应地创建一个 DT_INIT
条目。简版:使用
gcc
一步编译链接。如果需要,您可以使用
-Wl
(请参阅手册页)传递额外选项,例如 -soname
,例如 -Wl,-soname,libsmlib.so.1
。init_module()
,这显然是保留的或其他什么。将其更改为其他内容使一切正常。