【发布时间】:2017-05-06 22:30:25
【问题描述】:
如果我有以下用 C 语言编写的程序(在 Debian 8.7 上使用 GCC 编译),我可以像您期望的那样调用 atexit():
#include <stdlib.h>
void exit_handler(void) {
return;
}
int main () {
atexit(exit_handler);
return 0;
}
当我编译并运行它时:
$ gcc test.c
$ ./a.out
正如您所期望的那样,不输出任何内容。事实上,当我运行ldd 时,我得到:
$ ldd a.out
linux-vdso.so.1 (0x00007fffbe592000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe07d3a8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe07d753000)
不过libc似乎没有atexit的符号,amd只有__cxa_atexit和__cxa_threaded_atexit_impl:
$ nm --dynamic /lib/x86_64-linux-gnu/libc.so.6 | grep 'atexit'
0000000000037d90 T __cxa_atexit
0000000000037fa0 T __cxa_thread_atexit_impl
如您所料,如果我尝试动态链接到libc,我实际上无法调用atexit(),例如在以下链接到libc 并尝试查找atexit 的Racket 程序中:
#lang racket
(require ffi/unsafe)
(get-ffi-obj 'atexit (ffi-lib "libc" '("6")) (_fun (_fun -> _void) -> _int))
给出输出:
$ racket findatexit.rkt
ffi-obj: couldn't get "atexit" from "libc.so.6" (/lib/x86_64-linux-gnu/libc.so.6: undefined symbol: atexit)
这里我想知道的是:
- 如果
libc在Linux 上没有atexit的任何符号,为什么我仍然可以从C 程序中调用它? - 有什么方法可以在 Linux 上动态调用
atexit或类似函数?
(我应该注意到atexit 在 OS X 上确实是一个符号,所以它只是 Linux 在这里看起来不寻常。)
编辑:
在@Jonathan的建议下,我也跑了:
$ gcc -c test.c
$ nm test.o
U atexit
0000000000000000 T exit_handler
0000000000000007 T main
这似乎表明atexit 符号在某处,但它没有出现在ldd 显示的任何库中。
【问题讨论】:
-
试试
gcc -c test.c; nm test.o,看看那里引用了哪些符号。 -
好主意:``` $ nm test.o U atexit 0000000000000000 T exit_handler 0000000000000007 T main ```
-
好的;这意味着它以某种方式调用
atexit()。您是否查看过ld.so.1(或者,对您而言,可能是/lib64/ld-linux-x86-64.so.2)中的符号?或者crt0.o,或者任何相关的?您可能需要运行gcc -v test.c才能准确查看链接了哪些库和目标文件。 -
嗯...它似乎不存在,由以下人员确定:
$ nm --dynamic /lib64/ld-linux-x86-64.so.2 | grep 'atexit'
标签: c linux shared-libraries racket dynamic-linking