linux中nm、ldd、readelf命令

本文详细介绍了nm、ldd与readelf三个常用命令的功能与使用方法。nm用于列出目标文件的符号清单,有助于调查bug时定位问题;ldd用于显示可执行模块的依赖关系;readelf用于展示ELF格式目标文件的信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、nm

 

1.     说明:

nm用来列出目标文件的符号清单。Makefile中将产生的目标文件的符号清单列出,

调查bug时,可以工具清单中的信息准确定位问题。

 

2.     用法下面是nm命令的格式:

nm [-a│--debug-syms] [-g│--extern-only][-B] [-C│--demangle[=style]] [-D│--dynamic]

[-S│--print-size] [-s│--print-armap][-A│-o│--print-file-name][--special-syms]

[-n│-v│--numeric-sort][-p│--no-sort] [-r│--reverse-sort] [--size-sort]

[-u│--undefined-only][-t radix│--radix=radix] [-P│--portability]

[--target=bfdname] [-f format│--format=format][--defined-only] [-l│--line-numbers]

[--no-demangle] [-V│--version][-X 32_64] [--help]

         [objfile...]

                  -a或--debug-syms:显示所有的符号,包括debugger-onlysymbols。

                  -B:等同于--format=bsd,用来兼容MIPS的nm。

                  -C或--demangle:将低级符号名解析(demangle)成用户级名字。这样可以使得C++函数名具有可读性。

                  --no-demangle:默认的选项,不需要将低级符号名解析成用户级名。

                  -D或--dynamic:显示动态符号。该任选项仅对于动态目标(例如特定类型的共享库)有意义。

                  -fformat:使用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:按大小排列符号顺序。该大小是按照一个符号的值与它下一个符号的值进行计算的。

                  -tradix或--radix=radix:使用radix进制显示符号值。radix只能为"d"表示十进制、"o"表示八进制或"x"表示十六进制。

                  --target=bfdname:指定一个目标代码的格式,而非使用系统的默认格式。

                  -u或--undefined-only:仅显示没有定义的符号(那些外部符号)。

                  --defined-only:仅显示定义的符号。

                  -l或--line-numbers:对每个符号,使用调试信息来试图找到文件名和行号。对于已定义的符号,查找符号地址的行号。

                          对于未定义符号,查找符号重定位项的行号。如果可以找到行号信息,显示在符号信息之后。

                   -V或--version:显示nm的版本号。

                  --help:显示nm的任选项。

3.     输出结果对于每一个符号,

nm列出其值(the symbolvalue),类型(the symbol type)和其名字(the symbol name)。

对于每一个符号来说,其类型如果是小写的,则表明该符号是local的;大写则表明该符号是global(external)的。

符号/类型       说明

         A      该符号的值是绝对的,在以后的链接过程中,不允许进行改变。这样的符号值,常常出现在中断向量表中,

                  例如用符号来表示各个中断向量函数在中断向量表中的位置。

         B      该符号的值出现在非初始化数据段(bss)中。

                  例如,在一个文件中定义全局staticint test。则该符号test的类型为b,位于bss section中。

                  其值表示该符号在bss段中的偏移。一般而言,bss段分配于RAM中

         C      该符号为common。commonsymbol是未初始话数据段。该符号没有包含于一个普通section中。只有在链接过程中才进行分配。

                  符号的值表示该符号需要的字节数。例如在一个c文件中,定义int test,并且该符号在别的地方会被引用,

                  则该符号类型即为C。否则其类型为B。

         D      该符号位于初始话数据段中。一般来说,分配到datasection中。

                  例如定义全局intbaud_table[5] = {9600, 19200, 38400, 57600, 115200},则会分配于初始化数据段中。

         G      该符号也位于初始化数据段中。主要用于smallobject提高访问small data object的一种方式。

         I        该符号是对另一个符号的间接引用。

         N      该符号是一个debugging符号。

         R      该符号位于只读数据区。例如定义全局constint test[] = {123, 123};则test就是一个只读数据区的符号。

                  注意在cygwin下如果使用gcc直接编译成MZ格式时,源文件中的test对应_test,并且其符号类型为D,即初始化数据段中。

                  但是如果使用m6812-elf-gcc这样的交叉编译工具,源文件中的test对应目标文件的test,即没有添加下划线,并且其符号类型为R。

                  一般而言,位于rodatasection。值得注意的是,如果在一个函数中定义const char *test = “abc”, const char test_int = 3。

                  使用nm都不会得到符号信息,但是字符串“abc”分配于只读存储器中,test在rodata section中,大小为4。

         S       符号位于非初始化数据区,用于smallobject。

         T       该符号位于代码区text section。

         U      该符号在当前文件中是未定义的,即该符号的定义在别的文件中。例如,当前文件调用另一个文件中定义的函数,

                  在这个被调用的函数在当前就是未定义的;但是在定义它的文件中类型是T。

                  但是对于全局变量来说,在定义它的文件中,其符号类型为C,在使用它的文件中,其类型为U。

         V      该符号是一个weak object。

         W     The symbol is a weak symbol that has notbeen specifically tagged as a weak object symbol.

         -       该符号是a.out格式文件中的stabssymbol。

         ?       该符号类型没有定义

 

4.     举例test:

$(CXX) XXX -o $@ $(STRIP) $@ -o$@.strip$(SIZE) $@ > $@.nm$(NM) -n $@ >> $@.nm

 

 

二、LDD

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

2)、ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量,如下:LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、 LD_VERBOSE等。当LD_TRACE_LOADED_OBJECTS环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的 dependency,而程序并不真正执行。要不你可以在shell终端测试一下,如下:

 

(1) export LD_TRACE_LOADED_OBJECTS=1

(2) 再执行任何的程序,如ls等,看看程序的运行结果

 

3)、ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld-linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。

 

4)、实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2--list program(这相当于ldd program)

 

5)、ldd命令使用方法(摘自ldd --help)

 

名称 ldd - 打印共享库的依赖关系串5

 

大纲 ldd [选项]... 文件...字

 

描述 ldd 输出在命令行上指定的每个程序或共享库需要的共享库。

 

选项

 

--version

 

打印ldd的版本号

 

-v --verbose串3

 

打印所有信息,例如包括符号的版本信息

 

-d --data-relocs

 

执行符号重部署,并报告缺少的目标对象(只对ELF格式适用)

 

-r --function-relocs

 

对目标对象和函数执行重新部署,并报告缺少的目标对象和函数(只对ELF格式适用)

 

--help 用法信息

 

注意: ldd的标准版本与glibc2一起提供。Libc5与老版本以前提供,在一些系统中还存在。在libc5版本中长选项不支持。另一方面,glibc2版本不支持-V选项,只提供等价的--version选项。如果命令行中给定的库名字包含'/',这个程序的libc5版本将使用它作为库名字;否则它将在标准位置搜索库。运行一个当前目录下的共享库,加前缀"./"。

 

错误:

 

(1) ldd不能工作在a.out格式的共享库上。

 

(2) ldd不能工作在一些非常老的a.out程序上,这些程序在支持ldd的编译器发行前已经创建。如果你在这种类型的程序上使用ldd,程序将尝试argc = 0的运行方式,其结果不可预知。

 

 

三、readelf

 

readelf命令用来显示一个或者多个elf格式的目标文件的信息,可以通过它的选项来控制显示哪些信息。这里的elf-file(s)就表示那些被检查的文件。可以支持32位,64位的elf格式文件,也支持包含elf文件的文档(这里一般指的是使用ar命令将一些elf文件打包之后生成的例如lib*.a之类的“静态库”文件)。

 

选项

-a --all 显示全部信息,等价于 -h -l -S-s -r -d -V -A -I.

-h --file-header 显示elf文件开始的文件头信息.

-l --program-headers --segments 显示程序头(段头)信息(如果有的话)。

 -S--section-headers --sections 显示节头信息(如果有的话)。

-g --section-groups 显示节组信息(如果有的话)。

-t --section-details 显示节的详细信息(-S的)。

-s --syms --symbols 显示符号表段中的项(如果有的话)。

-e --headers 显示全部头信息,等价于: -h -l -S

-n --notes 显示note段(内核注释)的信息。

-r --relocs 显示可重定位段的信息。

-u --unwind 显示unwind段信息。当前只支持IA64ELF的unwind段信息。

-d --dynamic 显示动态段的信息。

-V --version-info 显示版本段的信息。

-A --arch-specific 显示CPU构架信息。

-D --use-dynamic 使用动态段中的符号表显示符号,而不是使用符号段。

 -x--hex-dump= 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名。

-w[liaprmfFsoR] or--debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]显示调试段中指定的内容。

-I --histogram 显示符号的时候,显示bucketlist长度的柱状图。

-v --version 显示readelf的版本信息。

-H --help 显示readelf所支持的命令行选项。

-W --wide 宽行输出。

@file 可以将选项集中到一个文件中,然后使用这个@file选项载入。

 

来自: http://man.linuxde.net/readelf

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值