Linux 共享库构造函数不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9472519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:52:21  来源:igfitidea点击:

shared library constructor not working

clinuxgccshared-libraries

提问by Manohar

In my shared library I have to do certain initialization at the load time. If I define the function with the GCC attribute __attribute__ ((constructor))it doesn't work, i.e. it doesn't get called when the program linking my shared library is loaded.

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

If I change the function name to _init(), it works. Apparently the usage of _init()and _fini()functions are not recommendednow.

如果我将函数名称更改为_init(),它就可以工作。显然现在不推荐使用_init()_fini()函数。

Any idea why __attribute__ ((constructor))wouldn't work? This is with Linux 2.6.9, gccversion 3.4.6

知道为什么__attribute__ ((constructor))不起作用吗?这是 Linux 2.6.9,gcc版本 3.4.6

Edit:

编辑:

For example, let's say the library code is this the following:

例如,假设库代码如下:

#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;
}

For building the .so I do the following:

为了构建 .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

Since the .so is not in one of the standard locations I update the LD_LIBRARY_PATHand link the .so from a another program. The constructor doesn't get called. If I change it to _init(), it works.

由于 .so 不在标准位置之一,我更新LD_LIBRARY_PATH并从另一个程序链接 .so。构造函数不会被调用。如果我将其更改为_init(),它会起作用。

采纳答案by Dan Fego

Okay, so I've taken a look at this, and it looks like what's happening is that your intermediate gccstep (using -c) is causing the issue. Here's my interpretation of what I'm seeing.

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

When you compile as a .owith setup(), gccjust treats it as a normal function (since you're not compiling as a .so, so it doesn't care). Then, lddoesn't see any _init()or anything like a DT_INITin the ELF's dynamic section, and assumes there's no constructors.

当您编译为.owith 时setup()gcc只需将其视为普通函数(因为您没有编译为.so,所以它不在乎)。然后,在 ELF 的动态部分ld中看不到任何_init()类似 aDT_INIT的内容,并假设没有构造函数。

When you compile as a .owith _init(), gccalso treats it as a normal function. In fact, it looks to me like the object files are identicalexcept for the names of the functions themselves! So once again, ldlooks at the .ofile, but this time sees a _init()function, which it knows it's looking for, and decides it's a constructor, and correspondingly creates a DT_INITentry in the new .so.

当您编译为.owith 时_init()gcc也将其视为普通函数。事实上,在我看来,除了函数本身的名称之外,目标文件是相同的!所以再次ld查看.o文件,但这次看到一个_init()函数,它知道它正在寻找,并确定它是一个构造函数,并相应地DT_INIT在 new 中创建一个条目.so

Finally, if you do the compilation and linking in one step, like this:

最后,如果你一步完成编译和链接,像这样:

gcc -Wall -shared -fPIC -o libsmlib.so smlib.c

Then what happens is that gccsees and understands the __attribute__ ((constructor))in the context of creating a shared object, and creates a DT_INITentry accordingly.

然后发生的事情是在创建共享对象的上下文中gcc看到并理解__attribute__ ((constructor)),并相应地创建一个DT_INIT条目。

Short version: use gccto compile and link in one step. You can use -Wl(see the man page) for passing in extra options like -sonameif required, like -Wl,-soname,libsmlib.so.1.

短版:用于gcc一步编译和链接。您可以使用-Wl(参见手册页)传递额外的选项,如-soname需要,如-Wl,-soname,libsmlib.so.1.

回答by Lunar Mushrooms

From this link:

这个链接

"Shared libraries must not be compiled with the gcc arguments -nostartfiles'' or-nostdlib''. If those arguments are used, the constructor/destructor routines will not be executed (unless special measures are taken)."

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

gcc/ld doesn't set the DT_INIT bit in the elf header when -nostdlib is used . You can check objdump -p and look for the section INIT in both cases. In attribute((constructor)) case you wont find that INIT section . But for __init case you will find INIT section in the shared library.

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