linux 为什么共享库fini函数在预加载到dash时没有被调用?

roejwanj  于 2023-03-17  发布在  Linux
关注(0)|答案(2)|浏览(143)

我使用的是最新的Ubuntu Linux。
下面是一个共享库,其中包含加载和卸载时调用的函数:
shared.c

#include <fcntl.h>
#include <sys/stat.h>

void init() {
    open("init", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
}

void fini() {
    open("fini", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
}

这是用
gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini shared.c -o shared.so
然后我这样做:

$ rm init fini
$ LD_PRELOAD=$PWD/shared.so  dash /dev/null
$ echo $?
0
$ ls init
init
$ ls fini
ls: cannot access 'fini': No such file or directory

因此...调用了加载函数,但未调用卸载函数
如果我用bash替换dash,两个都被调用。
使用__attribute__((destructor))没有什么区别。
为什么不调用dash的卸载函数?
根据Marco Bonelli的要求添加:

$ file $(which dash)
/usr/bin/dash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f7ab02fc1b8ff61b41647c1e16ec9d95ba5de9f0, for GNU/Linux 3.2.0, stripped

$ ldd $(which dash)
        linux-vdso.so.1 (0x00007ffd931c0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6b19e84000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6b1a0ec000)
ws51t4hk

ws51t4hk1#

为什么共享库fini函数在预加载到dash时没有被调用?
因为dash在这里调用_exit_exit在这里调用exit_group syscall,syscall立即终止程序。
我们再举一个小例子:

# Makefile
all:
        gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini -Wl,-soname,shared.so shared.c -o shared.so
        gcc main.c -o main.out
        LD_PRELOAD=$(PWD)/shared.so ./main.out /dev/null

# main.c
#include <unistd.h>
int main() {
        _exit(0);
}

# shared.c
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
void out(const char *str) {
        int fd = open("/dev/tty", O_WRONLY);
        write(fd, str, strlen(str));
        close(fd);
}
void init() {
        out("\nstart\n\n");
}
void fini() {
        out("\nstop\n\n");
}

执行时不输出停止:

$ make
gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini -Wl,-soname,shared.so shared.c -o shared.so
gcc main.c -o main.out
LD_PRELOAD=..../shared.so ./main.out /dev/null

start
6vl6ewon

6vl6ewon2#

我应该把这作为一个评论,但我把它作为一个答案的格式的目的。
问题不在于redirectiontouch之间的区别,因为在dash/touch运行中,shared.so被加载了两次,一次用于dash,一次用于touch。fini仅与touch一起触发。
您可以看到这两次运行的差异:

$ LD_PRELOAD=$PWD/shared.so  dash  /dev/null
# fini is not called
$ LD_PRELOAD=$PWD/shared.so  touch /dev/null
# fini is called

所以这和dash有关。
希望能为您的调查提供更多的资料。

相关问题