我在RedHat Linux 5.0提供功能的内部共享库free
和malloc
:
>nm ./libmem_consumption.so | grep -P -e "\bfree\b|\bmalloc\b"
0000000000006540 T free
00000000000088a0 T malloc
此共享库负责提供关于过程的存储器消耗的信息。 当它与Apache使用可惜的是有一个与此共享库的一个问题httpd
。 当Apache正在与此库运行,我得到一个核心转储libc::free
和信息的指针是无效的。 这个问题似乎是在http.so其是通过由加载libphp5.so加载的共享库httpd
。
其实,当我不加载http.so
一切正常,并没有转储。 (加载或不加载http.so
由指令在配置文件管理:延长= http.so)当我加载http.so
httpd进程核心转储。
httpd
是lauched这样:
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 =所有,并保存输出到一个文件我看到这些线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'
看来, LD_PRELOAD=./libmem_consumption.so
不用于http.so
当free
被查找。 为什么LD_PRELOAD被忽略?
它seeems是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: %d\n", 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
一切OK。
export UNSET_RTLD_DEEPBIND=1
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config
这是LD_DEBUG的输出=全部为UNSET_RTLD_DEEPBIND为1:
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'