The GNU linker链接器搜索共享库的顺序

来源:互联网 发布:数据填报系统 开源 编辑:程序博客网 时间:2024/06/06 03:14

ld - The GNU linker搜索共享库(shared library)的顺序。

更多详细信息可以参考man ld页面,关于一些动态库的知识可以参考另一篇博文“Linux ldd命令”

The linker uses the following search paths to locate required shared libraries:

  1. Any directories specified by -rpath-link options.
  2. Any directories specified by -rpath options.  The difference between -rpath and -rpath-link is that directories specified by-rpath options are included in the executable and used at runtime, whereas the-rpath-linkoption is only effective at link time. Searching-rpath in this way is only supported by native linkers and cross linkers which have been configured with the--with-sysroot option.
  3. On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".
  4. On SunOS, if the -rpath option was not used, search any directories specified using-L options.
  5. For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".
  6. For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.
  7. The default directories, normally /lib and /usr/lib.
  8. For a native linker on an ELF system, if the file/etc/ld.so.conf exists, the list of directories found in that file.

1. -rpath-link仅仅在link(链接)的时候有效。

2. -rapth将会存储在ELF文件里面,而且是在run(运行)的时候有效,-rpath仅仅支持native(本地) linker,和配置了--with-sysroot选项的cross(跨平台) linker。跨平台编译就是在一个平台上面编译了,在其他几个平台上也可以运行。

3. 在ELF系统里面,针对本地链接器,假如-rpath和-rpath-link选项都没有使用,将会搜索LD_RUN_PATH环境变量的内容。

4. 在SunOS系统里面,假如-rpath选项没有使用,将会搜索-L选项指定的内容。

5. 针对本地链接器,将会搜索LD_LIBRARY_PATH环境变量的内容。

6. 针对本地ELF链接器,将会搜索DT_RUNPATH和DT_RPATH环境变量的内容,如果DT_RUNPATH环境变量存在,那么DT_RPATH就会被忽略。

7. 默认的搜索路径是/lib和/usr/lib。

8. 针对在ELF系统里面的本地链接器,假如/etc/ld.so.conf存在,将会从里面包含的目录中搜索。

搜索顺序是从上到下,如果需要的共享库没有找到,链接器将会发出一个warning,并且继续后面的shared library的查询。


最近因为工作的需要研究了RPATH,现在给大家分享一下。以前我们编译的工具很多都是要依赖LD_LIBRARY_PATH来查找共享库,因为LD_LIBRARY_PATH不是那么好,所以就打算用利用RPATH把相关的共享库放到编译好的ELF里面。这里就举两个例子来说明怎么把RPATH加入到ELF里面,一个是编译cpp文件的时候加上RPATH,另外一个是在编译工具的时候,configure这步加上RPATH。

例子

编译单个的cpp文件,加入RPATH

[root@rhel6164 test]# cat memleak.cppint main(){    int* k = new int[10]; // memleak!    return 0;}[root@rhel6164 test]# g++ -Wl,-rpath=./lib memleak.cpp -o memleak #编译memleak可执行文件的时候,把-rpath参数加上,我这里就以当前路径下的lib目录为例,加入到rpath里面[root@rhel6164 test]# readelf -d ./memleak #查看RPATH已经加入到memleak可执行文件里面,到时候在运行memleak的时候,就会首先到指定的目录去找相应的共享库Dynamic section at offset 0x7d8 contains 24 entries:  Tag        Type                         Name/Value 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6] 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6] 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1] 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6] 0x000000000000000f (RPATH)              Library rpath: [./lib] 0x000000000000000c (INIT)               0x400480 0x000000000000000d (FINI)               0x4006c8 0x000000006ffffef5 (GNU_HASH)           0x400260 0x0000000000000005 (STRTAB)             0x400318 0x0000000000000006 (SYMTAB)             0x400288 0x000000000000000a (STRSZ)              171 (bytes) 0x000000000000000b (SYMENT)             24 (bytes) 0x0000000000000015 (DEBUG)              0x0 0x0000000000000003 (PLTGOT)             0x6009b0 0x0000000000000002 (PLTRELSZ)           72 (bytes) 0x0000000000000014 (PLTREL)             RELA 0x0000000000000017 (JMPREL)             0x400438 0x0000000000000007 (RELA)               0x400420 0x0000000000000008 (RELASZ)             24 (bytes) 0x0000000000000009 (RELAENT)            24 (bytes) 0x000000006ffffffe (VERNEED)            0x4003d0 0x000000006fffffff (VERNEEDNUM)         2 0x000000006ffffff0 (VERSYM)             0x4003c4 0x0000000000000000 (NULL)               0x0

我这里以python为例,从源码编译、安装python的时候,加入RPATH

[root@rhel6164 2.7.2]#tar xjf Python-2.7.2.tar.bz2 && cd Python-2.7.2 #解压源码包[root@rhel6164 2.7.2]#LDFLAGS='-Wl,-rpath=\$${ORIGIN}/../lib' ./configure --prefix=/root/package/python/2.7.2/install_with_rpath --enable-shared --enable-ipv6 --enable-unicode=ucs4 #定义LDFLAGS变量,这里用到了ORIGIN变量,意思是当前可执行文件所在的目录,也要enable共享库选项[root@rhel6164 2.7.2]#make && make install[root@rhel6164 2.7.2]# readelf -d ./install_with_rpath/bin/python2.7 #查看到RPATH已经加入到python2.7的可执行文件里面,到时候就不需要在设置LD_LIBRARY_PATH变量指定要找的共享库所在的目录Dynamic section at offset 0x8f0 contains 26 entries:  Tag        Type                         Name/Value 0x0000000000000001 (NEEDED)             Shared library: [libpython2.7.so.1.0] 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0] 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2] 0x0000000000000001 (NEEDED)             Shared library: [libutil.so.1] 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6] 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6] 0x000000000000000f (RPATH)              Library rpath: [${ORIGIN}/../lib] 0x000000000000000c (INIT)               0x4005e8 0x000000000000000d (FINI)               0x400808 0x000000006ffffef5 (GNU_HASH)           0x400260 0x0000000000000005 (STRTAB)             0x400458 0x0000000000000006 (SYMTAB)             0x4002c0 0x000000000000000a (STRSZ)              255 (bytes) 0x000000000000000b (SYMENT)             24 (bytes) 0x0000000000000015 (DEBUG)              0x0 0x0000000000000003 (PLTGOT)             0x600ae8 0x0000000000000002 (PLTRELSZ)           48 (bytes) 0x0000000000000014 (PLTREL)             RELA 0x0000000000000017 (JMPREL)             0x4005b8 0x0000000000000007 (RELA)               0x4005a0 0x0000000000000008 (RELASZ)             24 (bytes) 0x0000000000000009 (RELAENT)            24 (bytes) 0x000000006ffffffe (VERNEED)            0x400580 0x000000006fffffff (VERNEEDNUM)         1 0x000000006ffffff0 (VERSYM)             0x400558 0x0000000000000000 (NULL)               0x0


0 0
原创粉丝点击