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

huangapple go评论91阅读模式
英文:

why isn't shared library fini function called when preloaded to dash?

问题

我使用的是最新的Ubuntu Linux。

这是一个包含在加载和卸载时调用的函数的共享库:

shared.c

  1. #include <fcntl.h>
  2. #include <sys/stat.h>
  3. void init() {
  4. open("init", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  5. }
  6. void fini() {
  7. open("fini", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  8. }

它与以下命令编译:

gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini shared.c -o shared.so

然后我执行以下步骤:

  1. $ rm init fini
  2. $ LD_PRELOAD=$PWD/shared.so dash /dev/null
  3. $ echo $?
  4. 0
  5. $ ls init
  6. init
  7. $ ls fini
  8. ls: 无法访问'fini': 没有那个文件或目录

所以... 加载函数被调用,但卸载函数没有被调用。

如果我将dash替换为bash,两者都被调用。

使用__attribute__((destructor))没有任何区别。

为什么对于dash卸载函数没有被调用?

根据Marco Bonelli的请求添加:

  1. $ file $(which dash)
  2. /usr/bin/dash: ELF 64-bit LSB pie 可执行文件, 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
  3. $ ldd $(which dash)
  4. linux-vdso.so.1 (0x00007ffd931c0000)
  5. libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6b19e84000)
  6. /lib64/ld-linux-x86-64.so.2 (0x00007f6b1a0ec000)
英文:

I am on the latest Ubuntu Linux.

Here is a shared library with functions that are called when loading and unloading:

shared.c:

  1. #include &lt;fcntl.h&gt;
  2. #include &lt;sys/stat.h&gt;
  3. void init() {
  4. open(&quot;init&quot;, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  5. }
  6. void fini() {
  7. open(&quot;fini&quot;, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  8. }

and this is compiled with

gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini shared.c -o shared.so

and then I do this:

  1. $ rm init fini
  2. $ LD_PRELOAD=$PWD/shared.so dash /dev/null
  3. $ echo $?
  4. 0
  5. $ ls init
  6. init
  7. $ ls fini
  8. ls: cannot access &#39;fini&#39;: No such file or directory

So... loading function is called, but unloading function is not

If I replace dash with bash , both are called.

Using __attribute__((destructor)) does not make a difference.

Why isn't the unloading function called for dash?

Added per Marco Bonelli's request:

  1. $ file $(which dash)
  2. /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
  3. $ ldd $(which dash)
  4. linux-vdso.so.1 (0x00007ffd931c0000)
  5. libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6b19e84000)
  6. /lib64/ld-linux-x86-64.so.2 (0x00007f6b1a0ec000)

答案1

得分: 2

因为dash在这里调用_exit,它调用exit_group系统调用,这里立即终止程序。

让我们也做一个小例子:

  1. # Makefile
  2. all:
  3. gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini -Wl,-soname,shared.so shared.c -o shared.so
  4. gcc main.c -o main.out
  5. LD_PRELOAD=$(PWD)/shared.so ./main.out /dev/null
  6. # main.c
  7. #include <unistd.h>
  8. int main() {
  9. _exit(0);
  10. }
  11. # shared.c
  12. #include <fcntl.h>
  13. #include <sys/stat.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. void out(const char *str) {
  17. int fd = open("/dev/tty", O_WRONLY);
  18. write(fd, str, strlen(str));
  19. close(fd);
  20. }
  21. void init() {
  22. out("\nstart\n\n");
  23. }
  24. void fini() {
  25. out("\nstop\n\n");
  26. }

执行时不会输出"stop":

  1. $ make
  2. gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini -Wl,-soname,shared.so shared.c -o shared.so
  3. gcc main.c -o main.out
  4. LD_PRELOAD=..../shared.so ./main.out /dev/null
  5. start
英文:

> why isn't shared library fini function called when preloaded to dash?

Because dash calls _exit here which calls exit_group syscall here which terminates the program immediately.

Let's also do a small example:

  1. # Makefile
  2. all:
  3. gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini -Wl,-soname,shared.so shared.c -o shared.so
  4. gcc main.c -o main.out
  5. LD_PRELOAD=$(PWD)/shared.so ./main.out /dev/null
  6. # main.c
  7. #include &lt;unistd.h&gt;
  8. int main() {
  9. _exit(0);
  10. }
  11. # shared.c
  12. #include &lt;fcntl.h&gt;
  13. #include &lt;sys/stat.h&gt;
  14. #include &lt;unistd.h&gt;
  15. #include &lt;string.h&gt;
  16. void out(const char *str) {
  17. int fd = open(&quot;/dev/tty&quot;, O_WRONLY);
  18. write(fd, str, strlen(str));
  19. close(fd);
  20. }
  21. void init() {
  22. out(&quot;\nstart\n\n&quot;);
  23. }
  24. void fini() {
  25. out(&quot;\nstop\n\n&quot;);
  26. }

On execution does not output stop:

  1. $ make
  2. gcc -shared -fPIC -Wl,-init=init -Wl,-fini=fini -Wl,-soname,shared.so shared.c -o shared.so
  3. gcc main.c -o main.out
  4. LD_PRELOAD=..../shared.so ./main.out /dev/null
  5. start

答案2

得分: 1

问题不在于“redirection”和“touch”之间的区别,因为在您的“dash/touch”运行中,已加载了shared.so两次,一次用于dash,一次用于touch。
“fini”仅在“touch”中触发。

您可以通过以下两次运行来看到差异:

  1. $ LD_PRELOAD=$PWD/shared.so dash /dev/null
  2. # fini未被调用
  3. $ LD_PRELOAD=$PWD/shared.so touch /dev/null
  4. # fini被调用

因此,这与“dash”有关。

希望这为您的调查提供了更多材料。

英文:

I should have put this as a comment, but I put it as an answer for formatting purposes.

The problem is not about the difference between redirection and touch, because in your dash/touch run, shared.so has been loaded twice, once for dash, once for touch.
fini fired only with touch.

You can see the diffrence with these two runs :

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

So this has something to do with dash.

Hope this provide more materials for your investigation.

huangapple
  • 本文由 发表于 2023年3月7日 14:40:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75658705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定