为什么LD_PRELOAD不加载的共享库的一个工作吗?(Why LD_PRELOAD doesn&#

2019-08-02 17:54发布

我在RedHat Linux 5.0提供功能的内部共享库freemalloc

>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.sofree@pltlibmem_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.sofree被查找。 为什么LD_PRELOAD被忽略?

Answer 1:

它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'


文章来源: Why LD_PRELOAD doesn't work for one of loaded shared libraries?