这一章节目前是简短了一点;当我掠尽ELF HOWTO时,就是这部份再度扩展的时候了。
Linux有共享程序库,如果之前你已坐著读完上一章节,想必现在一听到像这样的说词,便会立刻感到头昏。有一些照惯例而言是在连结时期便该完成的工作,必须延迟到载入时期才能完成。
把你连结的错误寄给我!我不会做任何的事,不过我可以把它们写起来**
can't load library: /lib/libxxx.so, Incompatible version
(a. out only) 这是指你没有xxx程序库的正确的主要版本。可别以为随随 便便弄个连结到你目前拥有的版本就可以了,如果幸运的话,就只会造成你的程序分页错误而已。去抓新的版本.ELF类似的情况会造成像下面这样的信息:
ftp: can't load library 'libreadline.so.2'
warning using incompatible library version xxx
(a. out only)你的程序库的次要版本比起这支程序用来编译的还要旧。程序依然可以执行。只是可能啦!我想,升个级应该没什么伤害吧!
有一组环境变数会让动态载入器有所反应。大部份的环境变数对ldd
的用途要比起对一般users的还要来得更多。而且可以很方便的设定成由ldd配合各种参数来执行。这些变数包括,
LD_BIND_NOW
--- 正常来讲,函数在呼叫之前是不会让程序寻找的。设定这个旗号会使得程序库一载入,所有的寻找便会发生,同时也造成起始的时间较慢。当你想测试程序,确定所有的连结都没有问题时,这项旗号就变得很有用。
LD_PRELOAD
可以设定一个文档,使其具有*覆盖*函数定义的能力。例如,如果你要测试内存分配的方略,而且还想置换*malloc*,那么你可以写好准备替换的副程序,并把它编译成mallolc.
,然后:
$ LD_PRELOAD=malloc.o; export LD_PRELOAD
$ some_test_program
LD_ELF_PRELOAD
与 LD_AOUT_PRELOAD
很类似,但是仅适用于正确的二进位型态。如果设定了
LD_
something_PRELOAD
与 LD_PRELOAD
,比较明确的那一个会被用到。
LD_LIBRARY_PATH
是一连串以分号隔离的目录名称,用来搜寻共享程序库。对ld而言,并没有任何的影响;这项只有在执行期间才有影响。另外,对执行setuid与setgid的程序而言,这一项是无效的。而LD_ELF_LIBRARY_PATH
与LD_AOUT_LIBRARY_PATH
这两种旗号可根据各别的二进位型式分别导向不同的搜寻路径。一般正常的运作下,不应该会用到LD_LIBRARY_PATH
;把需要搜寻的目录加到/etc/ld.so.conf/
里;然后重新执行ldconfig。
LD_NOWARN
仅适用于a.out。一旦设定了这一项(LD_NOWARN=true; export LD_NOWARN
),它会告诉载入器必须处理fatal-warnings(像是次要版本不兼容等)的警告信息。
LD_WARN
仅适用于ELF。设定这一项时,它会将通常是致命信息的“Can*t find library”转换成警告信息。对正常的操作而言,这并没有多大的用处,可是对ldd就很重要了。
LD_TRACE_LOADED_OBJECTS
仅适用于ELF。而且会使得程序以为它们是由ldd
所执行的:
$ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx
libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
libc.so.5 => /lib/libc.so.5.2.18
如果你很熟悉Solaris 2.x所支持的动态载入的工作的话,你会发现Linux在这点上与其非常的相近。这一部份在H.J.Lu的ELF程序设计文件内与dlopen(3)
的manual page(可以在ld.so的套件上找到)上有广泛的讨论。这里有个不错的简单范例:以-ldl
连结。
#include <dlfcn.h>
#include <stdio.h>
main()
{
void *libc;
void (*printf_call)();
if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY))
{
printf_call=dlsym(libc,"printf");
(*printf_call)("hello, world\n");
}
}