Linux程序分析工具:ldd和nm(2)

 

xiaomanon@xiaomanon-machine:~/Documents/c_code$ nm tooltest 0804a038 B __bss_start 0804a038 b completed.6590 0804a02c D __data_start 0804a02c W data_start 08048450 t deregister_tm_clones 080484c0 t __do_global_dtors_aux 08049f0c t __do_global_dtors_aux_fini_array_entry 0804a030 D __dso_handle 08049f14 d _DYNAMIC 0804a038 D _edata 0804a03c B _end U exit@@GLIBC_2.0 08048674 T _fini U fork@@GLIBC_2.0 08048688 R _fp_hw 080484e0 t frame_dummy 08049f08 t __frame_dummy_init_array_entry 080487e0 r __FRAME_END__ 0804a034 D global 0804a000 d _GLOBAL_OFFSET_TABLE_ w __gmon_start__ 08048354 T _init 08049f0c t __init_array_end 08049f08 t __init_array_start 0804868c R _IO_stdin_used w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 08049f10 d __JCR_END__ 08049f10 d __JCR_LIST__ w _Jv_RegisterClasses 08048670 T __libc_csu_fini 08048600 T __libc_csu_init U __libc_start_main@@GLIBC_2.0 0804850d T main U malloc@@GLIBC_2.0 U perror@@GLIBC_2.0 U printf@@GLIBC_2.0 08048480 t register_tm_clones U sleep@@GLIBC_2.0 08048410 T _start 0804a038 D __TMC_END__ 08048440 T __x86.get_pc_thunk.bx

 

上面便是tooltest这个程序中所有的符号,首先介绍一下上面输出内容的格式:

■ 第一列:当前符号的地址。

■ 第二列:当前符号的类型(关于类型的说明,可以查看手册页man nm详细阅读)。

■ 第三列:当前符号的名称。

使用nm主要有一下几个方面的帮助:

(1) 判断指定的程序中有没有指定的符号,比较常用的方式为:nm –C program | grep symbol

(2) 解决程序编译时undefined reference的错误,以及multiple definition的错误。

(3) 查看某个符号的地址,以及在进程空间的大概位置(.bss, .data, .text段,具体可以通过第二列的类型来判断)。

部分符号类型说明

A : 该符号的值是绝对的,在以后的链接过程中,不允许进行改变。这样的符号值,常常出现在中断向量表中,例如用符号来表示各个中断向量函数在中断向量表中的位置。

B : 该符号的值出现在非初始化数据段(.bss)中。例如,在一个文件中定义全局static int test。则该符号test的类型为b,位于bss section中。其值表示该符号在bss段中的偏移。一般而言,bss段分配于RAM中 。

C : 该符号为common。common symbol是未初始话数据段。该符号没有包含于一个普通section中。只有在链接过程中才进行分配。符号的值表示该符号需要的字节数。例如在一个c文件中,定义int test,并且该符号在别的地方会被引用,则该符号类型即为C。否则其类型为B。

D : 该符号位于初始化数据段中。一般来说,分配到.data section中。例如定义全局int baud_table[5] = {9600, 19200, 38400, 57600, 115200},则会分配于初始化数据段中。

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

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

N : 该符号是一个debugging符号。

R : 该符号位于只读数据段。例如定义全局const int test[] = {123, 123};则test就是一个只读数据区的符号。注意在cygwin下如果使用gcc直接编译成MZ格式时,源文件中的test对应_test,并且其符号类型为D,即初始化数据段中。但是如果使用m6812-elf-gcc这样的交叉编译工具,源文件中的test对应目标文件的test,即没有添加下划线,并且其符号类型为R。一般而言,位于rodata section。值得注意的是,如果在一个函数中定义const char *test = “abc”, const char test_int = 3。使用nm都不会得到符号信息,但是字符串“abc”分配于只读存储器中,test在rodata section中,大小为4。

S : 符号位于非初始化数据段,用于small object。

T : 该符号位于代码段text section。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/17021.html