共享库构造函数不起作用

问题描述 投票:0回答:3

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

c linux gcc shared-libraries
3个回答
4
投票

好的,所以我已经查看了这个,看起来发生的情况是您的中间

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
    


2
投票
此链接

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

使用 -nostdlib 时,gcc/ld 不会在 elf 头中设置 DT_INIT 位。您可以检查 objdump -p 并在这两种情况下查找 INIT 部分。在

attribute

((constructor)) 情况下,您将找不到 INIT 部分。但对于 __init 情况,您会在共享库中找到 INIT 部分。


0
投票
init_module()

,这显然是保留的或其他什么。将其更改为其他内容使一切正常。

    

© www.soinside.com 2019 - 2024. All rights reserved.