提问人:Mark Galeck 提问时间:3/7/2023 最后编辑:Mark Galeck 更新时间:3/11/2023 访问量:115
为什么在预加载到达世币时没有调用共享库 fini 函数?
why isn't shared library fini function called when preloaded to dash?
问:
我使用的是最新的 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
所以。。。加载函数被调用,但卸载函数没有被调用
如果我用 替换 ,则两者都被调用。dash
bash
使用没有区别。__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)
答:
1赞
Philippe
3/8/2023
#1
我应该把它作为一个评论,但我把它放在一个答案上,用于格式化。
问题不在于 和 之间的区别,因为在破折号/触摸运行中,shared.so 被加载了两次,一次用于破折号,一次用于触摸。 仅用 .redirection
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
希望这能为您的调查提供更多材料。
评论
0赞
Mark Galeck
3/11/2023
感谢您指出这一点,我将根据您的观察修改和简化问题
2赞
KamilCuk
3/11/2023
#2
为什么在预加载到达世币时没有调用共享库 fini 函数?
因为 dash 调用 here 会调用 exit_group syscall here 会立即终止程序。_exit
我们再举一个小例子:
# 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
评论
0赞
Mark Galeck
3/11/2023
等。。。所以,当我查看官方手册页文档并谈到该选项时,这基本上毫无价值?因为如果主程序使用,则该函数将被忽略。换句话说,有什么意义 - 我把一些需要运行的代码放在那里,但主程序可以很容易地击败它,我的代码将无法运行。ld
-fini
_exit()
-fini
-fini
0赞
KamilCuk
3/11/2023
关键是立即退出。的重点是添加一个 finish 函数来退出。 主程序可以随时调用或执行分段故障。_exit
fini
the main program can easily defeat
abort()
0赞
Mark Galeck
3/11/2023
那么,我如何确保我的“完成”代码始终在预加载我的库的主程序退出后运行。没有办法吗??
0赞
Mark Galeck
3/11/2023
是的,我明白了。我搞砸了......如果我不能依靠我的代码完成执行,这对我来说是一个障碍。
0赞
KamilCuk
3/11/2023
how do I ensure that my "finishing"
将程序包装在父程序中。.使用进程管理器、服务编排器 - 或 等。bash -c 'trap "echo finishing task" EXIT; ./yourprogram'
systemd
systemd-run
评论
file $(which dash)
ldd $(which dash)
dash
dash
dash
dash
LD_PRELOAD
ldd $(shared.so)
strace -f dash -c "> /dev/null"
strace -f dash -c "touch /dev/null"
shared.so