为什么LD_PRELOAD不适用于其中一个加载的共享库?
Why LD_PRELOAD doesn't work for one of loaded shared libraries?
我在RedHat Linux 5.0上有一个内部共享库,提供函数free
和malloc
:
>nm ./libmem_consumption.so | grep -P -e "bfreeb|bmallocb"
0000000000006540 T free
00000000000088a0 T malloc
这个共享库负责提供有关进程内存消耗的信息。不幸的是,当这个共享库与Apachehttpd
一起使用时,它出现了问题。当Apachehttpd与这个库一起运行时,我在libc::free
中得到一个coredump,并得到一条指针无效的消息。问题似乎出在http.so中,这是一个由libphp5.加载的共享库,因此由httpd
加载。
事实上,当我不加载http.so
时,一切都很好,没有核心转储。(加载或不加载http.so
由配置文件中的指令管理:extension=http.so)当我加载http.so
时,httpd会处理coredumps。
httpd
是这样启动的:
LD_PRELOAD=./libmem_consumption.so ./bin/httpd -f config
以及退出时的核心转储。
当我将LD_BIND_NOW设置为1并且加载了http.so
时,我看到(在gdb下)http.so的free@plt
指向libc::free
,而在其他加载的中库(例如libphp5.so
)free@plt
指向libmem_consumption.so::free
。这怎么可能呢?
顺便说一句,当我导出LD_DEBUG=all并将输出保存到一个文件中时,我看到了libphp5.so(也已加载)的以下行:
25788: symbol=free; lookup in file=/apache2/bin/httpd [0]
25788: symbol=free; lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
25788: binding file /apache2/modules/libphp5.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free' [GLIBC_2.2.5]
http.so:完全不同
25825: symbol=free; lookup in file=/apache2/ext/http.so [0]
25825: symbol=free; lookup in file=/apache2/ps/lib/libz.so.1 [0]
25825: symbol=free; lookup in file=/apache2/ps/lib/libcurl.so.4 [0]
25825: symbol=free; lookup in file=/lib64/libc.so.6 [0]
25825: binding file /apache2/ext/http.so [0] to /lib64/libc.so.6 [0]: normal symbol `free'
当查找free
时,似乎LD_PRELOAD=./libmem_consumption.so
没有用于http.so
。为什么忽略LD_PRELOAD?
http.so加载时带有RTLD_DEEPBIND标志,这就是为什么其中一个共享库忽略LD_PRELOAD的原因。
这是来自http://linux.die.net/man/3/dlopen:
RTLD_DEEPBIND(自glibc 2.3.4起)将此库中符号的查找范围放在全局范围之前。这意味着一个独立的图书馆将使用拥有的符号优先于具有相同名称的全局符号包含在已加载的库中。此标志不是POSIX.1-2001中规定。
我写了一个测试共享库:
#include <dlfcn.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void initialize_my_dlopen(void) __attribute__((constructor));
void* (*real_dlopen)(const char *, int flag);
static int unset_RTLD_DEEPBIND=0;
static int _initialized = 0;
static void initialize_my_dlopen(void)
{
if (_initialized)
return;
real_dlopen = (void *(*)(const char *,int))dlsym(RTLD_NEXT, "dlopen");
unset_RTLD_DEEPBIND = atoi(getenv("UNSET_RTLD_DEEPBIND") ? getenv("UNSET_RTLD_DEEPBIND") : "0");
printf("unset_RTLD_DEEPBIND: %dn", unset_RTLD_DEEPBIND);
_initialized = 1;
}
extern "C" {
void *dlopen(const char *filename, int flag)
{
int new_flag = unset_RTLD_DEEPBIND == 0 ? flag : flag & (~RTLD_DEEPBIND);
return (*real_dlopen)(filename, new_flag);
}
}
并建立了它:
gcc -shared -fPIC -g -m64 my_dlopen.cpp -o libmy_dlopen.so -ldl
当我将UNSET_RTLD_DEEPBIND设置为0并运行httpd
时,程序将进行核心转储。
export UNSET_RTLD_DEEPBIND=0
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config
当我将UNSET_RTLD_DEEPBIND设置为1并运行httpd
时,一切正常。
export UNSET_RTLD_DEEPBIND=1
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config
这是UNSET_RTLD_DEEPBIND到1:的LD_DEBUG=all的输出
10678: symbol=free; lookup in file=/apache2/bin/httpd [0]
10678: symbol=free; lookup in file=/apache2/libmy_dlopen.so [0]
10678: symbol=free; lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
10678: binding file /apache2/ext/http.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free'
- 如何在C++中使用pybind11加载一个pickle python列表
- 我的程序有一个保存配置文件的GUI,如何双击此配置文件以直接加载带有配置数据的GUI?
- 如何制作一个只包含字符的简单加载屏幕
- 试图用c++制作一个动画加载圈
- SFML 将图像从 txt 文件加载到矢量中仅加载最后一个图像
- 当将多个TypedArrayContents数组加载到V8数组中时(数组数组)时,最后一个元素将覆盖所有元素
- Java加载DLL,该DLL从JNI中的另一个DLL导出方法
- 为什么主可执行文件和 dlopen 加载的共享库共享命名空间静态变量的一个副本?
- 如何使用 for 循环将元素加载到我的每个数组中,然后将每个数组的总和输出到一个 sum 数组中
- 如何在单独的线程上加载纹理到主内存并使用它在另一个线程上渲染
- 从一个文本文件加载多个 char 和 int 类型的数组
- 如何使用布尔值来防止在一个类中加载两次
- 为什么LD_PRELOAD不适用于其中一个加载的共享库?
- COCOS2D-X:从另一个线程中加载精灵,任何模式
- 这个opencv程序用于同时从一个文件夹中加载不同的图像,但它只读取一个图像
- 延迟加载可以被视为RAII的一个例子吗
- Qt:在另一个线程中预加载 qpixmap
- 是否有从另一个DLL中加载DLL的最佳实践
- 将一个大文件加载到内存中并在程序的所有运行时间内保持它是错误的
- 我的程序得到一个abort()错误,但我不能调试它,因为它是程序的一个加载部分