用 __attribute__((constructor)) 声明的函数被 LD_PRELOAD 多次调用
A function declared with __attribute__((constructor)) is invoked more than once with LD_PRELOAD
定义共享库如下:
#include <unistd.h>
#include <stdio.h>
static void init(void) __attribute__((constructor));
static void init(void)
{
fprintf(stderr, "pid=%u\n", (unsigned) getpid());
}
在 AMD64 机器上使用 GCC 10 构建:
gcc -shared -fPIC lib.c
运行 一个简单的验证过程:
$ LD_PRELOAD=`realpath a.out` ls
pid=15771
a.out lib.c
行 pid=15771
按预期由 init()
打印。
现在,重复生成子项和线程的复杂过程:
$ LD_PRELOAD=`realpath a.out` python3
pid=15835
pid=15835
pid=15835
pid=15835
pid=15839
pid=15844
pid=15835
pid=15835
pid=15846
pid=15846
pid=15847
pid=15847
pid=15849
pid=15849
pid=15851
pid=15852
pid=15853
pid=15853
pid=15856
pid=15857
pid=15857
pid=15858
pid=15858
pid=15861
pid=15862
pid=15862
pid=15865
pid=15868
pid=15835
Python 3.8.2 (default, Apr 19 2020, 18:33:14)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
观察到有像pid=15835
这样的重复条目,这表明init()
对于某些进程已经执行了不止一次。
为什么?
您的 Python 安装会在 Python 解释器启动时执行一些程序。如果使用 execve
替换进程映像,进程 ID 不会更改,但新进程映像的构造函数 运行。
一个更简单的示例如下所示:
$ LD_PRELOAD=`realpath a.out` bash -c 'exec /bin/true'
您可以通过调用 strace
:
查看更多详细信息
$ strace -f -E LD_PRELOAD=`realpath a.out` -eexecve bash -c 'exec /bin/true'
execve("/usr/bin/bash", ["bash", "-c", "exec /bin/true"], 0x55b275d8b830 /* 29 vars */) = 0
pid=801315
execve("/bin/true", ["/bin/true"], 0x5564dedbeb80 /* 29 vars */) = 0
pid=801315
+++ exited with 0 +++
定义共享库如下:
#include <unistd.h>
#include <stdio.h>
static void init(void) __attribute__((constructor));
static void init(void)
{
fprintf(stderr, "pid=%u\n", (unsigned) getpid());
}
在 AMD64 机器上使用 GCC 10 构建:
gcc -shared -fPIC lib.c
运行 一个简单的验证过程:
$ LD_PRELOAD=`realpath a.out` ls
pid=15771
a.out lib.c
行 pid=15771
按预期由 init()
打印。
现在,重复生成子项和线程的复杂过程:
$ LD_PRELOAD=`realpath a.out` python3
pid=15835
pid=15835
pid=15835
pid=15835
pid=15839
pid=15844
pid=15835
pid=15835
pid=15846
pid=15846
pid=15847
pid=15847
pid=15849
pid=15849
pid=15851
pid=15852
pid=15853
pid=15853
pid=15856
pid=15857
pid=15857
pid=15858
pid=15858
pid=15861
pid=15862
pid=15862
pid=15865
pid=15868
pid=15835
Python 3.8.2 (default, Apr 19 2020, 18:33:14)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
观察到有像pid=15835
这样的重复条目,这表明init()
对于某些进程已经执行了不止一次。
为什么?
您的 Python 安装会在 Python 解释器启动时执行一些程序。如果使用 execve
替换进程映像,进程 ID 不会更改,但新进程映像的构造函数 运行。
一个更简单的示例如下所示:
$ LD_PRELOAD=`realpath a.out` bash -c 'exec /bin/true'
您可以通过调用 strace
:
$ strace -f -E LD_PRELOAD=`realpath a.out` -eexecve bash -c 'exec /bin/true'
execve("/usr/bin/bash", ["bash", "-c", "exec /bin/true"], 0x55b275d8b830 /* 29 vars */) = 0
pid=801315
execve("/bin/true", ["/bin/true"], 0x5564dedbeb80 /* 29 vars */) = 0
pid=801315
+++ exited with 0 +++