“ldd”命令详解

ldd

ldd命令用于打印程序或者库文件所依赖的共享库列表。Glibc安装的库中有一个为ld-linux.so.X,其中X为一个数字,在不同的平台上名字也会不同。

1. 语法

Usage: ldd [OPTION]... FILE...
      --help              print this help and exit
      --version           print version information and exit
  -d, --data-relocs       process data relocations
  -r, --function-relocs   process data and function relocations
  -u, --unused            print unused direct dependencies
  -v, --verbose           print all information

2. 举例说明:

fan@carey:/$ ldd /bin/cat
        linux-vdso.so.1 (0x00007fff5cefb000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5412e04000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f5412fff000)

最后一个没有“=>”的就是当前平台下的ld-linux.so名称。其中第一个不是实际存在的库文件,它是一个虚拟库文件用于和kernel交互。

背景知识

1. ldd不是一个可执行程序,而只是一个shell脚本

fan@carey:~$ ldd /bin/ldd 
        not a dynamic executable

2.ldd实质是通过ld-linux.so(elf动态库的装载器)来实现的。

/lib/ld-linux.so.2以及它的64位版本/lib64/ld-linux-x86-64.so.2虽然看起来是共享库文件,但实际上他们可以独立运行。他们的功能是负责动态加载。它们通过读取可执行文件的头部信息来确定哪些库文件是必须的,以及哪些需要加载。加载完成后,它会通过修正执行文件里的相关的地址指针来和加载的库文件完成动态链接,此时程序就可以运行了。

  • 64位系统上可直接执行ld-linux-x86-64.so.2模块,如:
fan@carey:/$ /lib64/ld-linux-x86-64.so.2 --list /bin/cat
        linux-vdso.so.1 (0x00007fff94298000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa2d1ccc000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa2d1ec7000)

# 等价于:
fan@carey:/$ ldd /bin/cat
        linux-vdso.so.1 (0x00007fff3e115000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d54ca7000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4d54ea2000)

  • 32位系统上可直接执行ld-linux.so.2模块,如:
/lib/ld-linux.so.2 --list /bin/cat
等价于:
ldd /bin/cat

3. ld-linux.so查找共享库的顺序

3.1 以cat为例:

fan@carey:/$ ldd /bin/cat
        linux-vdso.so.1 (0x00007fff5cefb000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5412e04000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f5412fff000)
  1. cat告诉ld-linux.so它需要libc.so.6这个库文件,ld-linux.so将按一定顺序找到libc.so.6库再给cat调用。
  2. 因为ld-linux.so的位置是写死在程序中的(GCC在编译程序时就写死在里面了),GCC写到程序中ld-linux.so的位置是可以改变的,通过修改GCC的spec文件。
编译时,ld-linux.so查找共享库的顺序:
(1)ld-linux.so.6由gcc的spec文件中所设定
(2)gcc --print-search-dirs所打印出的路径,主要是libgcc_s.so等库。可以通过GCC_EXEC_PREFIX来设定
(3)LIBRARY_PATH环境变量中所设定的路径,或编译的命令行中指定的-L/usr/local/lib
(4)binutils中的ld所设定的缺省搜索路径顺序,编译binutils时指定。(可以通过“ld --verbose | grep SEARCH”来查看)
(5)二进制程序的搜索路径顺序为PATH环境变量中所设定。一般/usr/local/bin高于/usr/bin
(6)编译时的头文件的搜索路径顺序,与library的查找顺序类似。一般/usr/local/include高于/usr/include


运行时,ld-linux.so查找共享库的顺序:
(1)ld-linux.so.6在可执行的目标文件中被指定,可用readelf命令查看
(2)ld-linux.so.6缺省在/usr/lib和lib中搜索;当glibc安装到/usr/local下时,它查找/usr/local/lib
(3)LD_LIBRARY_PATH环境变量中所设定的路径
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路径,由ldconfig生成二进制的ld.so.cache中

3.2 注意:

其原理是通过设置一系列的环境变量,如下:LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、LD_VERBOSE等。当环境变量不为空时,运行任何可执行程序,都会只显示模块的dependency,而程序不会运行。例:

fan@carey:/usr/share/moeditor$ export LD_TRACE_LOADED_OBJECTS=1
fan@carey:/usr/share/moeditor$ ls
        linux-vdso.so.1 (0x00007ffc864c8000)
        libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fec92031000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fec91e6c000)
        libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007fec91ddc000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fec91dd6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fec92087000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fec91db4000)

引用出处

linux系统——ld-linux.so.X查找和加载共享动态库的顺序.

posted @ 2020-11-14 09:08  f_carey  阅读(108)  评论(0编辑  收藏  举报  来源