考虑以下库,可以在任何程序执行之前预先加载:
// g++ -std=c++11 -shared -fPIC preload.cpp -o preload.so
// LD_PRELOAD=./preload.so <command>
#include <iostream>
struct Goodbye {
Goodbye() {std::cout << "Hello\n";}
~Goodbye() {std::cout << "Goodbye!\n";}
} goodbye;
Run Code Online (Sandbox Code Playgroud)
问题是,虽然goodbye
总是调用全局变量的构造函数,但是没有为某些程序调用析构函数,例如ls
:
$ LD_PRELOAD=./preload.so ls
Hello
Run Code Online (Sandbox Code Playgroud)
对于其他一些程序,析构函数按预期调用:
$ LD_PRELOAD=./preload.so man
Hello
What manual page do you want?
Goodbye!
Run Code Online (Sandbox Code Playgroud)
你能解释为什么在第一种情况下没有调用析构函数吗?编辑:上面的问题已经得到解答,那就是程序可能会使用_exit(),abort()来退出.
然而:
有没有办法在预加载的程序退出时强制调用给定的函数?
我正在研究一个多线程的项目,并且想知道是否有办法让编译器标记使用对C库的非重入调用(例如strtok_r的strtok intsead)?如果没有,是否有一个不可重入的调用列表,所以我可以定期查看我的代码库?
一个相关的问题是,是否有办法标记3d方库使用非重入调用.
我假设重入意味着线程安全,但不一定反过来.是否有充分的理由在线程项目中使用非重入调用?
我正在写一个工具.该工具的一部分是它能够记录系统调用的参数.好吧,我可以ptrace
用于此目的,但ptrace
速度很慢.我想到的一种更快的方法是修改glibc.但这变得越来越困难,因为gcc神奇地将自己的内置函数作为系统调用包装器插入,而不是使用glibc中定义的代码.使用-fno-builtin
也没有帮助.
所以我提出了编写共享库的想法,其中包括每个系统调用包装器,例如mmap
然后在调用实际系统调用包装器函数之前执行日志记录.例如,mmap
下面给出了我的样子的伪代码.
int mmap(...)
{
log_parameters(...);
call_original_mmap(...);
...
}
Run Code Online (Sandbox Code Playgroud)
然后我可以使用LD_PRELOAD首先加载这个库.你觉得这个想法会起作用,还是我错过了什么?
无论如何在Linux(或更一般地说在POSIX OS中)保证在程序执行期间,即使文件被关闭而另一个文件被打开,也不会重复使用文件描述符?我的理解是,这种情况通常会导致已关闭文件的文件描述符被重新分配给新打开的文件.
我正在开发一个I/O跟踪项目,如果我可以假设在open()/ fopen()调用后,该文件描述符的所有后续I/O都是同一个文件,那么它会让生活更简单.
我将采用编译时或运行时解决方案.
如果这是不可能的,我可以做我自己的会计,当我处理跟踪文件(注意所有的打开和关闭通话的位置),但我更愿意被跟踪程序的执行过程中压制该问题.
我所知道的拦截系统调用的方法如下。
所以你看到上面提到的所有方法都有缺陷。所以我的问题是在不修改内核和最小开销的情况下拦截系统调用的方法是什么。
为了模拟某些行为,我想将探测附加到系统调用,并在传递某些参数时修改返回值.或者,在函数处理之前修改函数的参数也就足够了.
这可能与BPF有关吗?
linux ×7
c ×5
gcc ×3
system-calls ×3
c++ ×2
x86-64 ×2
bpf ×1
ebpf ×1
glibc ×1
io ×1
ld ×1
ld-preload ×1
posix ×1
reentrancy ×1
unix ×1