首页 > 解决方案 > Xlinker 入口参数在 Linux 中不起作用

问题描述

许多年前,我创建了一个库,它在加载到内存时自动执行代码。

我使用 -Xlinker --init=_entry,其中 _entry 是我的库中的一个符号。部分 Makefile 代码附在下面:

gcc -ggdb -fPIC -c ./cli2gui.c
gcc -ggdb -shared -Wl,-soname,cli2gui.so.0 -o cli2gui.so.0.1 ./cli2gui.o -Xlinker --init=_entry -lutil -ldl

一切都可以编译,但是在执行链接到我的库的程序(或动态加载它)时,没有执行 _entry。我通过在 gdb 中设置断点来检查这一点。

如何解决这个问题 - 我的意思是每次我的库加载到内存时如何执行 _entry?

标签: clinuxgcclinker

解决方案


__attribute__((constructor))如果您只添加function 属性,GCC(和 Clang)将为您处理详细信息。函数不需要有外部可见的符号,因为该属性告诉编译器和链接器将函数的地址添加到 init 部分,从而导致动态链接器(如果动态链接)或 C 运行时(如果静态链接)在 main() 之前执行函数。

一个简单的例子:

// SPDX-License-Identifier: CC0-1.0
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

static int wrerr(const char *src)
{
    if (!src || !*src)
        return 0;

    const int   saved_errno = errno;
    const char *end = src;

    while (*end)
        end++;

    while (src < end) {
        ssize_t  n = write(STDERR_FILENO, src, (size_t)(end - src));
        if (n > 0) {
            src += n;
        } else
        if (n != -1) {
            errno = saved_errno;
            return EIO;
        } else {
            const int  retval = errno;
            errno = saved_errno;
            return retval;
        }
    }

    errno = saved_errno;
    return 0;
}

__attribute__((constructor))
static void my_init(void)
{
    wrerr("my_init() called\n");
}

要进行测试,您可以将其编译为另一个程序中的目标文件,也可以将其编译为动态库并在运行时插入:

gcc -Wall -fPIC example.c -shared -Wl,-soname,libexample.so -ldl -o libexample.so
LD_PRELOAD=./libexample.so date

推荐阅读