我正在制作一个拦截库(在Linux上);我在运行需要使用它的应用程序之前预先加载它。这是为了执行重定向。
在我的库中,我有
__attribute__ constructor(())
来设置在对我的库中定义的调用进行任何解析之前需要运行的环境。
现在,我的假设是,在运行时,将在对此库中定义的函数做出任何解析之前调用此构造函数。例如,假设我正在拦截
ioctl
函数。我的假设是动态链接器只会在 __attribute__ constructor(())
运行之后解析任何调用(并调用它们);或者至少在第一次调用 ioctl
时运行 ctor,并且加载器正在解析它。
但令我惊讶的是,ctor 却出现了延迟(平均 17-30 毫秒)。确实呼叫了 ctor,但延迟了。在 ctor 执行之前,有一些调用被重定向到我的 ioctl
版本。
我尝试了解程序加载之间发生的事情,但得出任何结论都很困难。我真的很感激知道这样的执行背后的细节。
我编译共享库的方式是:
g++ my_lib.cpp -shared -fPIC -o my_lib.so
然后,我将其与我的应用程序一起加载:
LD_PRELOAD="./my_lib.so" ./{application_executable}
现在,我的假设是,在运行时,将在对此库中定义的函数做出任何解析之前调用此构造函数。
这确实是一个合理的期望。
但令我惊讶的是,ctor 竟然出现了延迟(平均 17-30 毫秒)。确实呼叫了 ctor,但延迟了。在 ctor 执行之前,有一些调用被重定向到我的 ioctl 版本。
有几种可能的解释:
ld-linux
本身调用ioctl
作为其自身初始化的一部分constructor
例程会调用ioctl
本身constructor
在没有更多细节的情况下,无法判断以上哪个原因才是真正的原因。
调试此问题的一种方法是将无限循环放入您的
ioctl
插入器中(参见例如此 answer),然后运行程序。它应该阻止。一旦完成,将调试器附加到它,并找出 where ioctl
是从哪里调用的。