LD_PRELOAD对PHP extension失效的原因

最近写了一个主机健康检测和软负载均衡用的软件ZFOR(http://github.com/chaoslawful/zfor ),可以通过LD_PRELOAD预载入的方式拦截系统的域名解析调用(gethostbyname、getaddrinfo等)。但发现对某些发行版的PHP CURL extension光加载zfor动态库没有用,还必须同时加载libcurl.so才能生效。

 

经过一番搜索,发现原来是PHP编译时让Zend引擎使用了RTLD_DEEPBIND标志来加载扩展,该标志的作用是约束动态符号解析的查找范围为载入的动态库及其依赖项,而不是从所有已加载项的符号表中寻找。PHP启用该选项的原意是避免同时加载多个具有共同依赖库的扩展时产生多版本符号解析冲突的问题,但在这里就影响了zfor的preload拦截过程。因为PHP CURL扩展只依赖libcurl.so而不依赖libzfor.so,故在不预加载libcurl.so时libzfor.so不会列入PHP CURL扩展符号解析的查找范围,这样在libzfor.so中定义的getaddrinfo别名自然无法生效。

 

在同时预加载libcurl.so和libzfor.so时,由于是系统的动态库加载器ld-linux.so按默认解析策略进行符号解析,故会将libcurl.so中引用的getaddrinfo符号解析到libzfor.so中提供的实现上,而由于动态库都是单实例加载的,这样当PHP CURL扩展被载入时,其依赖的libcurl.so就会用之前预加载的那个实例来解决,不需要再进行符号查找,也就不用受到RTLD_DEEPBIND标志的约束了。

 

你可能感兴趣的:(PHP,linux,搜索引擎,Zend)