Linux程序分析工具:ldd和nm
ldd和nm是Linux下两个非常实用的程序分析工具。其中,ldd是用来分析程序运行时需要依赖的动态链接库的工具,nm是用来查看指定程序中的符号表信息的工具。
1 ldd
格式:ldd [options] file
功能:列出file运行所需的共享库
参数:
-d 执行重定位并报告所有丢失的函数
-r 执行对函数和对象的重定位并报告丢失的任何函数或对象
tanghuaming@Thm:~/Documents/sys_programming$ whereis ldd
ldd: /usr/bin/ldd /usr/share/man/man1/ldd..gz
tanghuaming@Thm:~/Documents/sys_programming$ ll /usr/bin/ldd
-rwxr-xr-x root root 3月 : /usr/bin/ldd*
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等,看看程序的运行结果。
ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld-linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。
实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2 --list program(这相当于ldd program)ldd命令使用方法(摘自ldd --help)
我们选择一段待测试的应用程序,代码如下:
//@file tooltest.c
//@brief resource sharing between parent-process and sub-process
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int global = ; /*global variable, stored at data section*/ int main(void)
{
pid_t pid;//to store pid value
int stack = ;//local variable, stored at stack
int *heap;//pointer to a heap variable heap = (int *)malloc(sizeof(int));
*heap = ;//set the heap value to 2 pid = fork();//create a new process
if (pid < )
{
//error
perror("fail to fork");
exit(-);
}
else if (pid == )
{
//sub-process, change values
global++;
stack++;
(*heap)++;
//print all values
printf("In sub-process, global: %d, stack: %d, heap: %d\n", global, stack, *heap);
exit();
}
else
{
//parent process
sleep();//sleep 2 secends to make sure the sub-process runs first
printf("In parent-process, global: %d, stack: %d, heap: %d\n", global, stack, *heap);
} return ;
}
然后,我们编译并运行ldd命令:
xiaomanon@xiaomanon-machine:~/Documents/c_code$ ldd tooltest
linux-gate.so. => (0xb775b000)
libc.so. => /lib/i386-linux-gnu/libc.so. (0xb7595000)
/lib/ld-linux.so. (0xb775c000)
我们可以将ldd的输出结果分为3列来看:
■ 第一列:程序需要依赖什么库
■ 第二列:系统提供的与程序需要的库对应的库名称
■ 第三列:依赖库加载的开始地址
通过上面的这些信息,我们可以总结出下面的用途:
(1) 通过对比第一列和第二列,我们可以知道程序需要的动态链接库和系统实际提供的是否相比配。
(2) 通过第三列,我们可以知道当前动态链接库中的符号在进程地址空间中的起始位置。
2 nm
格式:nm [options] file
功能:列出file中的所有符号
参数:
-C 将符号转化为用户级的名字
-s 当用于.a文件即静态库时,输出把符号名映射到定义该符号的模块或成员名的索引
-u 显示在file外定义的符号或没有定义的符号
-l 显示每个符号的行号,或为定义符号的重定义项
下面是运行nm命令的输出结果:
xiaomanon@xiaomanon-machine:~/Documents/c_code$ nm tooltest
0804a038 B __bss_start
0804a038 b completed.
0804a02c D __data_start
0804a02c W data_start
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.
T _fini
U fork@@GLIBC_2.
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__
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
T __libc_csu_fini
T __libc_csu_init
U __libc_start_main@@GLIBC_2.
0804850d T main
U malloc@@GLIBC_2.
U perror@@GLIBC_2.
U printf@@GLIBC_2.
t register_tm_clones
U sleep@@GLIBC_2.
T _start
0804a038 D __TMC_END__
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。
U : 该符号在当前文件中是未定义的,即该符号的定义在别的文件中。例如,当前文件调用另一个文件中定义的函数,在这个被调用的函数在当前就是未定义的;但是在定义它的文件中类型是T。但是对于全局变量来说,在定义它的文件中,其符号类型为C,在使用它的文件中,其类型为U。
V : 该符号是一个weak object。
W : The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.
- : 该符号是a.out格式文件中的stabs symbol。
? : 该符号类型没有定义。
Linux程序分析工具:ldd和nm的更多相关文章
- linux程序分析工具
ldd和nm是Linux下两个非常实用的程序分析工具.ldd是用来分析程序运行时需要依赖的动态链接库的工具,nm是用来查看指定程序中的符号表信息的工具,objdump用来查看源代码与汇编代码,-d只查 ...
- Linux程序分析工具介绍—ldd,nm
原文链接:http://blog.csdn.net/statdm/article/details/7759100 本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具.ldd是用来分析 ...
- linux程序分析工具介绍(二)—-ldd,nm
本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具.ldd是用来分析程序运行时需要依赖的动态库的工具:nm是用来查看指定程序中的符号表相关内容的工具.下面通过例子,分别来介绍一下这两 ...
- linux程序分析工具介绍(一)—-”/proc”
写在最前面:在开始本文之前,笔者认为先有必要介绍一下linux下的man,如果读者手头用linux系统,直接在终端输入man man便可以看到详细的说明,我在这里简单的总结一下,man命令是用来查看l ...
- linux程序分析工具介绍(三)——sar
本文要介绍的sar,是linux下用来分析系统本身运行情况的非常有用的工具.我们知道,程序在操作系统上要运行,要关注的点不外乎内存,CPU和IO(包括磁盘IO和网络IO).我们的应用程序在操作系统中运 ...
- Linux资源分析工具杂谈(长文慎入)
Linux资源分析工具杂谈 开篇之前请大家先思考一个问题: 磁盘的平均I/O响应时间是1 ms,这个指标是好,还是差? 众所周知,计算机科学是客观的,也就是说对于一个给定的问题,我们总是 ...
- (转)超全整理!Linux性能分析工具汇总合集
超全整理!Linux性能分析工具汇总合集 原文:http://rdc.hundsun.com/portal/article/731.html 出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望, ...
- Linux 日志分析工具(logwatch)安装及使用
Linux 日志分析工具(logwatch)安装及使用 日志是非常重要的系统文件,管理员每天的重要工作就是分析和查看服务器的日志,判断服务器的健康状态.但是日志管理又是一项非常枯燥的工作,如果需要管理 ...
- Linux性能分析工具的安装和使用
转自:http://blog.chinaunix.net/uid-26488891-id-3118279.html Normal 0 7.8 磅 0 2 false false false EN-US ...
随机推荐
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
一个不错的UI多线程操作类 http://www.cnblogs.com/net66/archive/2005/08/03/206132.html
- [ActionScript 3.0] AS3 获取函数参数个数
function createFunction(param1:String,param2:String,param3:int=0):void { trace(arguments.length);//a ...
- relative和absolute的效果
我对这样几个效果不是特别理解: 1.float的效果: 就是搞不清楚我想要什么效果的时候可以将某个标签设置为float,一直没总结出什么规律. 2.relative和absolute的效果: 也是不清 ...
- Quartz.net一个简要示例
下面描述了一个Quartz.net最常用的应用场景,按特定秒数触发执行特定任务. 1.任务要继承自:IJob,在Execute方法中填入自己需要执行的任务. public virtual void E ...
- 使用 Heka 导入自定义的nginx日志到Elasticsearch
重置Heka执行进度 heka的进度配置文件存在配置项 base_dir 设置的目录,只需要删除这个文件夹下面的内容,就可以完全重置heka的进度. base_dir 配置项默认是在下面目录: '/v ...
- dwr NoSuchBeanDefinitionException
使用SpringMVC spring dwr时,dwr使用的bean,要将bean配置到根webapplicationcontext中,即applicationContext.xml中, 不能放到d ...
- VS打包资源文件,转自推酷,请小星同学查看
上篇博客把收费系统的总体设计进行了一遍讲解,讲解的同时掺杂了些有关.NET编译机制的总结.程序编写测试完成后接下来我们要做的是打包部署程序,但VS2012让人心痛的是没有了打包工具.不知道出于什么原因 ...
- cookie机制和session机制的原理和区别[转]
一.cookie机制和session机制的区别 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. 同时我们也看到,由于在服务器端保持状态的 ...
- Android——TableLayout
TableLayout的行数由开发人员直接指定,即有多少个TableRow对象(或View控件),就有多少行. TableLayout的列数等于含有最多子控件的TableRow的列数.如第一Table ...
- 初学cocos2dx-3.x之使用Scale9Sprite时的配置问题
今天学习的时候遇到了Scale9Sprite————一张可拉伸的精灵,只要给它设置一下大小,它就会自动拉伸. Scale9Sprite* nineGirl = Scale9Sprite::create ...