Prayer

在一般中寻求卓越
posts - 1256, comments - 190, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Linux程序分析工具介绍—ldd,nm

Posted on 2019-04-03 15:56 Prayer 阅读(367) 评论(0)  编辑 收藏 引用 所属分类: C/C++LINUX/UNIX/AIX

本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具。ldd是用来分析程序运行时需要依赖的动态库的工具;nm是用来查看指定程序中的符号表相关内容的工具。下面通过例子,分别来介绍一下这两个工具:

1. ldd, 先看下面的例子, 用ldd查看cs程序所依赖的动态库:

  1. $ ldd cs  
  2. linux-gate.so.1 =>  (0xffffe000)  
  3. libz.so.1 => /lib/libz.so.1 (0xb7f8c000)  
  4. libpthread.so.0 => /lib/libpthread.so.0 (0xb7f75000)  
  5. libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8 (0xb7e4d000)  
  6. libpcre.so.0 => /usr/lib/libpcre.so.0 (0xb7e21000)  
  7. libstdc++.so.6 => /usr/local/gcc4.5.1/lib/libstdc++.so.6 (0xb7d40000)  
  8. libm.so.6 => /lib/libm.so.6 (0xb7d18000)  
  9. libgcc_s.so.1 => /usr/local/gcc4.5.1/lib/libgcc_s.so.1 (0xb7cfd000)  
  10. libc.so.6 => /lib/libc.so.6 (0xb7bbc000)  
  11. /lib/ld-linux.so.2 (0xb7fab000)  
  12. libdl.so.2 => /lib/libdl.so.2 (0xb7bb7000)  

在上面的例子中,ldd的结果可以分为三列来看:

•第一列:程序需要依赖什么库
•第二列: 系统提供的与程序需要的库所对应的库
•第三列:库加载的开始地址
通过上面的信息,我们可以得到以下几个信息:

•(1) 通过对比第一列和第二列,我们可以分析程序需要依赖的库和系统实际提供的,是否相匹配
•(2) 通过观察第三列,我们可以知道在当前的库中的符号在对应的进程的地址空间中的开始位置
2. nm, 通过下面的例子,我们来介绍nm工具:

先看一下这个简单的程序:

  1. #include "iostream"   
  2.    
  3. using namespace std;  
  4.    
  5. class Test  
  6. {  
  7. public:  
  8.     void Hello()  
  9.     {  
  10.         cout < < "Hello world!" << endl;  
  11.     }  
  12. };  
  13.    
  14. int main()  
  15. {  
  16.     Test test;  
  17.     test.Hello();  
  18. }  

接下来,我们编译该程序,然后看nm的结果:

  1. $ g++ test.cc -o test  
  2. c$ nm test  
  3. 08049f10 d _DYNAMIC  
  4. 08049ff4 d _GLOBAL_OFFSET_TABLE_  
  5. 080486f0 t _GLOBAL__I_main  
  6. 080487fc R _IO_stdin_used  
  7.          w _Jv_RegisterClasses  
  8. 080486b0 t _Z41__static_initialization_and_destruction_0ii  
  9. 0804870c W _ZN4Test5HelloEv  
  10.          U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4  
  11.          U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4  
  12.          U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4  
  13. 0804a040 B _ZSt4cout@@GLIBCXX_3.4  
  14.          U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4  
  15. 0804a0d4 b _ZStL8__ioinit  
  16.          U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4  
  17. 08049f00 d __CTOR_END__  
  18. 08049ef8 d __CTOR_LIST__  
  19. 08049f08 D __DTOR_END__  
  20. 08049f04 d __DTOR_LIST__  
  21. 080488c8 r __FRAME_END__  
  22. 08049f0c d __JCR_END__  
  23. 08049f0c d __JCR_LIST__  
  24. 0804a02c A __bss_start  
  25.          U __cxa_atexit@@GLIBC_2.1.3  
  26. 0804a024 D __data_start  
  27. 080487b0 t __do_global_ctors_aux  
  28. 08048610 t __do_global_dtors_aux  
  29. 0804a028 D __dso_handle  
  30.          w __gmon_start__  
  31.          U __gxx_personality_v0@@CXXABI_1.3  
  32. 080487aa T __i686.get_pc_thunk.bx  
  33. 08049ef8 d __init_array_end  
  34. 08049ef8 d __init_array_start  
  35. 08048740 T __libc_csu_fini  
  36. 08048750 T __libc_csu_init  
  37.          U __libc_start_main@@GLIBC_2.0  
  38. 0804a02c A _edata  
  39. 0804a0d8 A _end  
  40. 080487dc T _fini  
  41. 080487f8 R _fp_hw  
  42. 08048508 T _init  
  43. 080485e0 T _start  
  44. 0804a0cc b completed.7065  
  45. 0804a024 W data_start  
  46. 0804a0d0 b dtor_idx.7067  
  47. 08048670 t frame_dummy  
  48. 08048694 T main  

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

•第一列:当前符号的地址
•第二列:当前符号的类型
•第三列:当前符号的名称
在上面的结果中,像_ZN4Test5HelloEv这样的符号,很多读者朋友可能会被它搞晕,这里介绍个小技巧,在nm的时候,加上-C选项,就可以把这些难以识别的符号,转换成便于我们阅读的符号TestHello()。这个主要是c++中的mangle机制所导致的,加上-C就是指定列出的符号是demangle了的。说了这么多,到底nm对我们程序有啥具体的帮助呢,我觉得主要有以下几个方面:
(1)判断指定程序中有没有定义指定的符号 (比较常用的方式:nm -C proc | grep symbol)
(2)解决程序编译时undefined reference的错误,以及mutiple definition的错误

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

本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具。ldd是用来分析程序运行时需要依赖的动态库的工具;nm是用来查看指定程序中的符号表相关内容的工具。下面通过例子,分别来介绍一

相关推荐


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理