linux下查看程序依赖的库

在x86下,为了查看程序所依赖的库,可以使用ldd命令

但如果是使用arm-linux-gcc 等交叉编译环境编译出来的程序,则要使用readelf命令来查看了

库用于将相似函数打包在一个单元中。然后这些单元就可为其他开发人员所共享,并因此有了模块化编程这种说法 — 即,从模块中构建程序。Linux 支持两种类型的库,每一种库都有各自的优缺点。静态库包含在编译时静态绑定到一个程序的函数。动态库则不同,它是在加载应用程序时被加载的,而且它与应用程序是在运行时绑定的。图 1 展示了 Linux 中的库的层次结构。

使用共享库的方法有两种:您既可以在运行时动态链接库,也可以动态加载库并在程序控制之下使用它们。本文对这两种方法都做了探讨。

静态库较适宜于较小的应用程序,因为它们只需要最小限度的函数。而对于需要多个库的应用程序来说,则适合使用共享库,因为它们可以减少应用程序对内存(包括运行时中的磁盘占用和内存占用)的占用。这是因为多个应用程序可以同时使用一个共享库;因此,每次只需要在内存上复制一个库。要是静态库的话,每一个运行的程序都要有一份库的副本。

GNU/Linux 提供两种处理共享库的方法(每种方法都源于 Sun Solaris)。您可以动态地将程序和共享库链接并让 Linux 在执行时加载库(如果它已经在内存中了,则无需再加载)。另外一种方法是使用一个称为动态加载的过程,这样程序可以有选择地调用库中的函数。使用动态加载过程,程序可以先加载一个特定的库(已加载则不必),然后调用该库中的某一特定函数(图 2 展示了这两种方法)。这是构建支持插件的应用程序的一个普遍的方法。

Linux 提供了很多种查看和解析 ELF 对象(包括共享库)的工具。其中最有用的一个当属ldd 命令,您可以使用它来发送共享库依赖项。例如,在 dl 应用程序上使用 ldd 命令会显示如下内容:

mtj@camus:~/dl$ ldd dl linux-gate.so.1 => (0xffffe000) libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7fdb000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7eac000) /lib/ld-linux.so.2 (0xb7fe7000)mtj@camus:~/dl$

ldd 所告诉您的是:该 ELF 映像依赖于 linux-gate.so(一个特殊的共享对象,它处理系统调用,它在文件系统中无关联文件)、libdl.so(DL API)、GNU C 库(libc.so)以及 Linux 动态加载器(因为它里面有共享库依赖项)。

readelf 命令是一个有很多特性的实用程序,它让您能够解析和读取 ELF 对象。readelf 有一个有趣的用途,就是用来识别对象内可再定位的项。对于我们这个简单的程序来说(清单 2展示的程序),您可以看到需要再定位的符号为:

mtj@camus:~/dl$ readelf -r dlRelocation section '.rel.dyn' at offset 0x520 contains 2 entries: Offset Info Type Sym.Value Sym. Name08049a3c 00001806 R_386_GLOB_DAT 00000000 __gmon_start__08049a78 00001405 R_386_COPY 08049a78 stdinRelocation section '.rel.plt' at offset 0x530 contains 8 entries: Offset Info Type Sym.Value Sym. Name08049a4c 00000207 R_386_JUMP_SLOT 00000000 dlsym08049a50 00000607 R_386_JUMP_SLOT 00000000 fgets08049a54 00000b07 R_386_JUMP_SLOT 00000000 dlerror08049a58 00000c07 R_386_JUMP_SLOT 00000000 __libc_start_main08049a5c 00000e07 R_386_JUMP_SLOT 00000000 printf08049a60 00001007 R_386_JUMP_SLOT 00000000 dlclose08049a64 00001107 R_386_JUMP_SLOT 00000000 sscanf08049a68 00001907 R_386_JUMP_SLOT 00000000 dlopenmtj@camus:~/dl$

从这个列表中,您可以看到各种各样的需要再定位(到 libc.so)的 C 库调用,包括对 DL API(libdl.so)的调用。函数 __libc_start_main 是一个 C 库函数,它优先于程序的 main 函数(一个提供必要初始化的 shell)而被调用。

其他操作对象文件的实用程序包括:objdump,它展示了关于对象文件的信息;nm,它列出来自对象文件(包括调试信息)的符号。还可以将 EFL 程序作为参数,直接调用 Linux 动态链接器,从而手动启动映像:

mtj@camus:~/dl$ /lib/ld-linux.so.2 ./dllibm.so expf 0.0 1.000000>

另外,可以使用 ld-linux.so 的 --list 选项来罗列 ELF 映像的依赖项(ldd 命令也如此)。切记,它仅仅是一个用户空间程序,是由内核在需要时引导的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值