Show me the money
分类: LINUX
2011-03-24 15:08:07
以前一直不理解连接参数-soname的用处。最近在项目实施过程中遇到共享库连接和运行的一些问题,终于才明白了设置这个参数的用意。
下面举例说明:
gcc –O2 -o foo -Wl,-rpath=. main.c libs1.so ../x1/libs2.so |
查看一下foo中的符号信息
$readelf -a foo | grep Shared 0x00000001 (NEEDED) Shared library: [libs1.so] 0x00000001 (NEEDED) Shared library: [../x1/libs2.so] 0x00000001 (NEEDED) Shared library: [libc.so.6] |
dynamic linker在初始化foo的时候,会认为libs2.so的位置为../x1,如果libs2.so不在这个位置,那么foo是无法正常运行的,因为dynamic linker会认为libs2.so找不到。
$./foo ./foo: error while loading shared libraries: ../x1/libs2.so: cannot open shared object file: No such file or directory |
这样就会带来麻烦,假设连接应用程序的时候某个shared library不在当前目录下,并且文件名不符合libXXX.so的形式,那么连接参数就只能使用 ../dir1/myshlib.so 这样的形式,无法变成等价的参数形式:-L../dir1 -lXXX。这样运行的是就要求myshlib.so必须放在相对路径../dir1中。如果myshlib.so以绝对路径/A/B/C/myshlib.so的形式表示,那么运行时就要求myshlib.so也放在目录/A/B/C中。
为了解决这个问题,ELF引入了DT_SONAME。在生成shared library的时候指定参数-soname=NAME。这样,用shared library去连接应用程序的时候,即使shared library是以什么形式给出(相对路径或者绝对路径),连接器都以NAME作为该shared library的名字。
gcc -shared -Wl,-soname=libs1.so.1 -o libs1.so s1.c && ln -sf libs1.so libs1.so.1 gcc -shared -Wl,-soname=libs2.so.1 -o libs2.so s2.c && ln -sf libs2.so libs2.so.1 gcc -O2 -o foo -Wl,-rpath=. main.c libs1.so ../x1/libs2.so $readelf -a foo | grep Shared 0x00000001 (NEEDED) Shared library: [libs1.so.1] 0x00000001 (NEEDED) Shared library: [libs2.so.1] 0x00000001 (NEEDED) Shared library: [libc.so.6] |
稍微解释一下过程:连接器在连接时发现../x1/libs2.so存在一个DT_SONAME的符号,它的值为libs2.so.1,因此,连接器取libs2.so.1作为shared library的名字,替代掉../x1.libs2.so。但是-soname=libs2.so.1并不会自动生成文件libs2.so.1,因此我们需要手动生成一个符号链接lib2.so.1,使之指向libs2.so,这样运行的时候就不会产生“找不到文件”的错误。
总结一下,在linux下使用shared library需要注意一下几个问题:
1. 生成shared library的时候使用-soname参数
2. 生成符号链接文件
3. 将shared library放入到LD_LIBRARY_PATH指定的目录中