Linux共享库概述( 四 )


另外 , FreeBSD使用cache的文件不一样 。 FreeBSD的ELF cache是/var/run/ld-elf.so.hints , 而a.out的cache则是/var/run/ld.so.hints 。 它们同样是通过ldconfig来更新 。
环境变量各种各样的环境变量控制着一些关键的过程 。 例如你可以临时为你特定的程序的一次执行指定一个不同的函数库 。 Linux系统中 , 通常变量LD_LIBRARY_PATH就是可以用来指定函数库查找路径的 , 而且这个路径通常是在查找标准的路径之前查找 。 这个是很有用的 , 特别是在调试一个新的函数库的时候 , 或者在特殊的场合使用一个非标准的函数库的时候 。 环境变量LD_PRELOAD列出了所有共享函数库中需要优先加载的库文件 , 功能和/etc/ld.so.preload类似 。 这些都是有/lib/ld-linux.so这个loader来实现的 。 值得一提的是 , LD_LIBRARY_PATH可以在大部分的UNIX-linke系统下正常起作用 , 但是并非所有的系统下都可以使用 , 例如HP-UX系统下 , 就是用SHLIB_PATH这个变量 , 而在AIX下则使用LIBPATH这个变量 。
LD_LIBRARY_PATH在开发和调试过程中经常大量使用 , 但是不应该被一个普通用户在安装过程中被安装程序修改 , 大家可以去参考~barr/ldpath.html,这里有一个文档专门介绍为什么不使用LD_LIBRARY_PATH这个变量 。
事实上还有更多的环境变量影响着程序的调入过程 , 它们的名字通常就是以LD_或者RTLD_打头 。 大部分这些环境变量的使用的文档都是不全 , 通常搞得人头昏眼花的 , 如果要真正弄清楚它们的用法 , 最好去读loader的源码(也就是gcc的一部分) 。
允许用户控制动态链接函数库将涉及到setuid/setgid这个函数 , 如果特殊的功能需要的话 。 因此 , GNU loader通常限制或者忽略用户对这些变量使用setuid和setgid 。 如果loader通过判断程序的相关环境变量判断程序的是否使用了setuid或者setgid , 如果uid和euid不同 , 或者gid和egid部一样 , 那么loader就假定程序已经使用了setuid或者setgid , 然后就大大的限制器控制这个老链接的权限 。 如果阅读GNU glibc的库函数源码 , 就可以清楚地看到这一点 。 特别的我们可以看elf/rtld.c和sysdeps/generic/dl-sysdep.c这两个文件 。 这就意味着如果你使得uid和gid与euid和egid分别相等 , 然后调用一个程序 , 那么这些变量就可以完全起效 。
3.4 创建一个共享函数库现在我们开始学习如何创建一个共享函数库 。 其实创建一个共享函数库非常容易 。 首先创建object文件 , 这个文件将加入通过gcc –fPIC参数命令加入到共享函数库里面 。 PIC的意思是“位置无关代码”(Position Independent Code) 。 下面是一个标准的格式:
gcc -shared -Wl,-soname,your_soname -o library_name file_list library_list
下面再给一个例子 , 它创建两个object文件(a.o和b.o) , 然后创建一个包含a.o和b.o的共享函数库 。 例子中”-g”和“-Wall”参数不是必须的 。
gcc -fPIC -g -c -Wall a.c
gcc -fPIC -g -c -Wall b.c
gcc -shared -Wl,-soname,liblusterstuff.so.1 -o liblusterstuff.so.1.0.1 a.o b.o -lc
下面是一些需要注意的地方:
不用使用-fomit-frame-pointer这个编译参数除非你不得不这样 。 虽然使用了这个参数获得的函数库仍然可以使用 , 但是这使得调试程序几乎没有用 , 无法跟踪调试 。
使用-fPIC来产生代码 , 而不是-fpic 。
某些情况下 , 使用gcc 来生成object文件 , 需要使用“-Wl,-export-dynamic”这个选项参数 。
通常 , 动态函数库的符号表里面包含了这些动态的对象的符号 。 这个选项在创建ELF格式的文件时候 , 会将所有的符号加入到动态符号表中 。 可以参考ld的帮助获得更详细的说明 。
3.5. 安装和使用共享函数库
一旦你定义了一个共享函数库 , 你还需要安装它 。 其实简单的方法就是拷贝你的库文件到指定的标准的目录(例如/usr/lib) , 然后运行ldconfig 。