在我的共享库中,我必须在加载时进行某些初始化。如果我使用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()
,则可以。
答案 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部分。