我熟悉使用dlopen()
检查共享库是否已使用事先调用dlopen()
加载到进程中,如果它不存在则不会触发加载,像这样:
void* lib = dlopen(lib_name, RTLD_NOLOAD);
if (lib != NULL) {
...
}
我最近尝试应用相同的模式来确定是否已使用LD_PRELOAD将少数共享库中的一个加载到进程空间中。但是,在所有情况下,上述对dlopen()
的调用都会返回NULL
。
所以基本上,如果我使用这个命令行启动进程
LD_PRELOAD=libawesome.so ./mycoolprocess
然后在mycoolprocess.c
中的代码中运行以下检查void* has_awesome = dlopen("libawesome.so", RTLD_NOLOAD);
if (has_awesome != NULL) {
printf("libawesome is available\n");
}
对dlopen()
的调用始终返回NULL
,无论是否使用LD_PRELOAD加载了共享库。根据Andrew Henle在下面的评论,我也尝试使用其中一个重新加载的共享对象的绝对路径调用dlopen
,但是在这种情况下dlopen
仍然返回NULL,尽管共享对象是预加载的。
所以我的问题有两个:
答案 0 :(得分:3)
不,是的,分别是。
dlopen()
和LD_PRELOAD技巧虽然它们都处理共享库,但却以完全不同的方式运行。
LD_PRELOAD环境变量由动态链接器/加载器(ld-linux.so)处理,并影响可执行二进制文件本身中的重定位记录的解析。简而言之,在代码中调用动态库中定义的函数的每个点,链接器(在构建时)将插入占位符以便跳转到内存地址。在运行时,这些占位符由基于加载到内存中的共享库的实际地址替换,这些共享库本身在可执行文件中命名,但如果使用LD_PRELOAD则可以覆盖。
因此,一旦将可执行文件加载到内存中并且所有这些占位符都填充了真实地址,就没有简单(或可移植)的方式来告诉来自哪里。然而...
你可以检查正在运行的进程的内存映射。在Linux上,这意味着通过/ proc /< pid> / maps进行解析。文件内容是相当不言自明的,所以只需随机选择一个并查看。
不知道你是如何在其他系统上做的,但我相信大多数现代unixen都有某种/ proc文件系统。