共享库构造函数不工作

时间:2012-02-27 21:25:41

标签: c linux gcc shared-libraries

在我的共享库中,我必须在加载时进行某些初始化。如果我使用GCC属性__attribute__ ((constructor))定义函数它不起作用,即在加载链接我的共享库的程序时不会调用它。

如果我将函数名称更改为_init(),则可以正常工作。显然,_init()_fini()函数的使用现在为not recommended

知道为什么__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(),则可以。

2 个答案:

答案 0 :(得分:4)

好的,我已经看过这个了,看起来正在发生的事情是你的中间gcc步骤(使用-c)导致了这个问题。这是我对所见所闻的解释。

当您使用.o编译为setup()时,gcc只会将其视为正常函数(因为您未编译为.so,因此它不会不在乎。然后,ld在ELF的动态部分中看不到任何_init()或类似DT_INIT的内容,并假设没有构造函数。

当您使用.o编译为_init()时,gcc也将其视为普通函数。事实上,它看起来像目标文件是相同的除了函数本身的名称!所以ld再一次查看.o文件,但这次看到_init()函数,它知道它正在查找,并确定它是构造函数,并相应地创建一个{{} 1}}在新DT_INIT中输入。

最后,如果你在一个步骤中进行编译和链接,就像这样:

.so

然后会发生的事情是gcc -Wall -shared -fPIC -o libsmlib.so smlib.c 在创建共享对象的上下文中看到并理解gcc,并相应地创建__attribute__ ((constructor))条目。

简短版本:使用DT_INIT一步编译和链接。如果需要,您可以使用gcc(参见手册页)传递-Wl等额外选项,例如-soname

答案 1 :(得分:2)

来自this link

“不能使用gcc参数-nostartfiles''或-nostdlib''编译共享库。如果使用这些参数,则不会执行构造函数/析构函数例程(除非采取特殊措施)。”

当使用-nostdlib时,gcc / ld不会在elf标头中设置DT_INIT位。您可以检查objdump -p并在两种情况下查找INIT部分。在属性((构造函数))的情况下,你不会找到INIT部分。但对于__init情况,您将在共享库中找到INIT部分。