一、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