linux 二进制文件分析工具

语法:ldd参数 文件

作用: 输出共享库的依赖信息

例如:

        # ldd /bin/cat
        libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

说明:ldd参数较少,其实ldd不是一个程序,仅仅是一个脚本,通过设置一系列环境变量实现。其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld-linux.so模块会先于可执行模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的依赖。如果其注意到环境变量LD_TRACE_LOADED_OBJECTS 被设置了,那么它就不会去执行那个可运行的程序,而去输出这个可执行程序所依赖的动态链接库 (在BSD 系统上的`ldd` 是一个C 程序)。

例如:

# export LD_TRACE_LOADED_OBJECTS=1
# ls
librt.so.1 => /lib64/librt.so.1 (0x0000002a9566d000)
libc.so.6 => /lib64/libc.so.6 (0x0000002a95786000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000002a959a8000)
/lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)
# unset LD_TRACE_LOADED_OBJECTS
# ls
bin   dev  home  ...

参数:

-d –data-relocs       输出数据重定位信息。并报告缺少的目标对象(only for ELF) ; LD_WARN=yes
-r --function-relocs  输出数据和函数重定位信息。并报告缺少的目标对象和函数(只对ELF格式适用) ; LD_WARN和LD_BIND_NOW=yes
-u, --unused            输出未使用的直接依赖  LD_DEBUG=“unused”
-v, --verbose          打印所有信息; LD_VERBOSE=yes

环境变量:

LD_TRACE_LOADED_OBJECTS

LD_LIBRARY_PATH:

LD_WARN

LD_BIND_NOW

LD_LIBRARY_VERSION

LD_VERBOS

示例:

定义两个文件:

fun.c 中有一个函数 int fun();

main.c调用 fun.c中的函数fun();

将fun.c编译成动态库:

# gcc -fPIC -shared fun.c -o fun.so

编译main.c

# gcc main.c ./fun.so -o main

查看用到的共享库:

# ldd main
linux-gate.so.1 => (0x00970000)
./fun.so (0x00871000)
libc.so.6 => /lib/i686/nosegneg/libc.so.6 (0x00339000)
/lib/ld-linux.so.2 (0x0031a000)

其它: Linux库管理命令

  1. ldconfig: 例如替换了库的链接 /lib/libc.so.6 -> libc-2.3.2.so   =>  /lib/libc.so.6 -> libc-2.3.4.so,就需要使用ldconfig命令更新。相关文件ld.so.conf, ld.so.cache。
  2. ldd : Tells what libraries a given program needs to run.
  3. ld.so/ld-linux.so: Dynamic linker/loader.

nm

nm:用来列出目标文件的符号清单。所谓符号,通常指定义出的函数,全局变量等等。

语法:

nm 参数 对象文件

描述:

nm列出目标文件的符号,如果没有目标文件,默认是a.out文件。输出内容包括3个内容:

  • 符号值:以选项选定基数输出符号值,默认是16进制。
  • 符号类型:
  • A 该符号的值是绝对的,在以后的链接过程中,不允许进行改变。(如符号__bss_start)
  • B 符号位于未初始化数据段(BSS)
  • C 符号该符号为common。common symbol是未初始话数据段。
  • D 该符号处于初始化数据段(如定义个全局变量: char * str = “hello”; 符号:str)
  • T 该符号位于代码区text section。(如符号:main)
  • N 该符号是一个debugging符号。
  • U 该符号未定义过,需要自其他对象文件中链接进来;
  • W 未明确指定的弱链接符号;同链接的其他对象文件中有它的定义就用上,否则就用一个系统特别指定的默认值。
  • ...
  • 符号名称

参数:

  • -a或--debug-syms:显示调试符号。
  • -B:等同于--format=bsd,用来兼容MIPS的nm。
  • -C或--demangle:将低级符号名解码(demangle)成用户级名字。这样能够使得C++函数名具备可读性。
  • -D或--dynamic:显示动态符号。该任选项仅对于动态目标(例如特定类型的共享库)有意义。
  • -f format:使用format格式输出。format能够选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd。
  • -g或--extern-only:仅显示外部符号。
  • -n、-v或--numeric-sort:按符号对应地址的顺序排序,而非按符号名的字符顺序。
  • -p或--no-sort:按目标文档中碰到的符号顺序显示,不排序。
  • -P或--portability:使用POSIX.2标准输出格式代替默认的输出格式。等同于使用任选项-f posix。
  • -s或--print-armap:当列出库中成员的符号时,包含索引。索引的内容包含:哪些模块包含哪些名字的映射。
  • -r或--reverse-sort:反转排序的顺序(例如,升序变为降序)。
  • --size-sort:按大小排列符号顺序。该大小是按照一个符号的值和他下一个符号的值进行计算的。
  • -t radix或--radix=radix:使用radix进制显示符号值。radix只能为"d"表示十进制、"o"表示八进制或"x"表示十六进制。
  • --target=bfdname:指定一个目标代码的格式,而非使用系统的默认格式。
  • -u或--undefined-only:仅显示没有定义的符号(那些外部符号)。
  • -l或--line-numbers:对每个符号,使用调试信息来试图找到文档名和行号。对于已定义的符号,查找符号地址的行号。对于未定义符号,查找指向符号重定位入口的行号。假如能够找到行号信息,显示在符号信息之后。

注意几点:

  • -C 总是适用于c++编译出来的对象文件。还记得c++中有重载么?为了区分重载函数,c++编译器会将函数返回值/参数等信息附加到函数名称中去形成一个mangle过的符号,那用这个选项列出符号的时候,做一个逆操作,输出那些原始的、我们可理解的符号名称。
  • 使用 -l 时,必须保证你的对象文件中带有符号调式信息,这一般要求你在编译的时候指定一个 -g 选项,见 Linux:Gcc
  • 使用nm前,最好先用Linux:File查看对象文件所属处理器架构,然后再用相应交叉版本的nm工具。

举例

更详细的内容见man page。这里举例说明:

nm -u hello.o

显示hello.o 中的未定义符号,需要和其他对象文件进行链接.
nm -A /usr/lib/* 2>/dev/null | grep "T memset"

在 /usr/lib/ 目录下找出哪个库文件定义了memset函数.

原文链接: https://www.cnblogs.com/wangshide/archive/2012/11/28/2793509.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    linux 二进制文件分析工具

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/70887

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午2:32
下一篇 2023年2月9日 下午2:33

相关推荐