转:http://blog.csdn.net/stpeace/article/details/47089585
一般来说, 搞linux开发的人, 才会用到nm命令, 非开发的人, 应该用不到。 虽然nm很简单, 但是还是有必要写几句, 聊表心意。
nm不是ni ma的缩写, 当然, 也不是ni mei的缩写, 而是names的缩写, nm命令主要是用来列出某些文件中的符号(说白了就是一些函数和全局变量等)。 下面, 我们一起来看看。
test.h为:
- void print();
void print();
test.c为:
- #include <stdio.h>
- #include "test.h"
- void print()
- {
- printf("rainy days\n");
- }
#include <stdio.h>
#include "test.h" void print()
{
printf("rainy days\n");
}
main.c为:
- #include "test.h"
- int main()
- {
- print();
- return 0;
- }
#include "test.h" int main()
{
print();
return 0;
}
好, 我们看看nm命令的作用效果, 如下:
- [taoge@localhost learn_nm]$ nm *
- nm: main.c: File format not recognized
- nm: test.c: File format not recognized
- nm: test.h: File format not recognized
- [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ nm *
nm: main.c: File format not recognized
nm: test.c: File format not recognized
nm: test.h: File format not recognized
[taoge@localhost learn_nm]$
ni ma, 啥都没有, 这说明nm对这类文件无用。
继续看nm能否读取目标文件和可执行文件:
- [taoge@localhost learn_nm]$ ls
- main.c test.c test.h
- [taoge@localhost learn_nm]$ gcc -c test.c main.c
- [taoge@localhost learn_nm]$ gcc test.o main.o
- [taoge@localhost learn_nm]$ ./a.out
- rainy days
- [taoge@localhost learn_nm]$ nm *
- a.out:
- 08049564 d _DYNAMIC
- 08049630 d _GLOBAL_OFFSET_TABLE_
- 0804849c R _IO_stdin_used
- w _Jv_RegisterClasses
- 08049554 d __CTOR_END__
- 08049550 d __CTOR_LIST__
- 0804955c D __DTOR_END__
- 08049558 d __DTOR_LIST__
- 0804854c r __FRAME_END__
- 08049560 d __JCR_END__
- 08049560 d __JCR_LIST__
- 0804964c A __bss_start
- 08049648 D __data_start
- 08048450 t __do_global_ctors_aux
- 08048330 t __do_global_dtors_aux
- 080484a0 R __dso_handle
- w __gmon_start__
- 0804844a T __i686.get_pc_thunk.bx
- 08049550 d __init_array_end
- 08049550 d __init_array_start
- 080483e0 T __libc_csu_fini
- 080483f0 T __libc_csu_init
- U __libc_start_main@@GLIBC_2.0
- 0804964c A _edata
- 08049654 A _end
- 0804847c T _fini
- 08048498 R _fp_hw
- 08048290 T _init
- 08048300 T _start
- 0804964c b completed.5963
- 08049648 W data_start
- 08049650 b dtor_idx.5965
- 08048390 t frame_dummy
- 080483c8 T main
- 080483b4 T print
- U puts@@GLIBC_2.0
- nm: main.c: File format not recognized
- main.o:
- 00000000 T main
- U print
- nm: test.c: File format not recognized
- nm: test.h: File format not recognized
- test.o:
- 00000000 T print
- U puts
- [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
main.c test.c test.h
[taoge@localhost learn_nm]$ gcc -c test.c main.c
[taoge@localhost learn_nm]$ gcc test.o main.o
[taoge@localhost learn_nm]$ ./a.out
rainy days
[taoge@localhost learn_nm]$ nm * a.out:
08049564 d _DYNAMIC
08049630 d _GLOBAL_OFFSET_TABLE_
0804849c R _IO_stdin_used
w _Jv_RegisterClasses
08049554 d __CTOR_END__
08049550 d __CTOR_LIST__
0804955c D __DTOR_END__
08049558 d __DTOR_LIST__
0804854c r __FRAME_END__
08049560 d __JCR_END__
08049560 d __JCR_LIST__
0804964c A __bss_start
08049648 D __data_start
08048450 t __do_global_ctors_aux
08048330 t __do_global_dtors_aux
080484a0 R __dso_handle
w __gmon_start__
0804844a T __i686.get_pc_thunk.bx
08049550 d __init_array_end
08049550 d __init_array_start
080483e0 T __libc_csu_fini
080483f0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804964c A _edata
08049654 A _end
0804847c T _fini
08048498 R _fp_hw
08048290 T _init
08048300 T _start
0804964c b completed.5963
08049648 W data_start
08049650 b dtor_idx.5965
08048390 t frame_dummy
080483c8 T main
080483b4 T print
U puts@@GLIBC_2.0
nm: main.c: File format not recognized main.o:
00000000 T main
U print
nm: test.c: File format not recognized
nm: test.h: File format not recognized test.o:
00000000 T print
U puts
[taoge@localhost learn_nm]$
可以看到, 对于目标文件和可执行文件而言, 均可以获得其中的函数, 如print函数。
我们继续看静态库和动态库, 如下:
- [taoge@localhost learn_nm]$ ls
- main.c test.c test.h
- [taoge@localhost learn_nm]$ gcc -c test.c
- [taoge@localhost learn_nm]$ ar rcs libtest.a test.o
- [taoge@localhost learn_nm]$ gcc -shared -fPIC -o libtest.so test.o
- [taoge@localhost learn_nm]$ ls
- libtest.a libtest.so main.c test.c test.h test.o
- [taoge@localhost learn_nm]$ nm lib*
- libtest.a:
- test.o:
- 00000000 T print
- U puts
- libtest.so:
- 000014bc a _DYNAMIC
- 00001590 a _GLOBAL_OFFSET_TABLE_
- w _Jv_RegisterClasses
- 000014a8 d __CTOR_END__
- 000014a4 d __CTOR_LIST__
- 000014b0 d __DTOR_END__
- 000014ac d __DTOR_LIST__
- 000004a0 r __FRAME_END__
- 000014b4 d __JCR_END__
- 000014b4 d __JCR_LIST__
- 000015a4 A __bss_start
- w __cxa_finalize@@GLIBC_2.1.3
- 00000440 t __do_global_ctors_aux
- 00000350 t __do_global_dtors_aux
- 000014b8 d __dso_handle
- w __gmon_start__
- 00000419 t __i686.get_pc_thunk.bx
- 000015a4 A _edata
- 000015ac A _end
- 00000478 T _fini
- 000002ec T _init
- 000015a4 b completed.5963
- 000015a8 b dtor_idx.5965
- 000003e0 t frame_dummy
- 00000420 T print
- U puts@@GLIBC_2.0
- [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
main.c test.c test.h
[taoge@localhost learn_nm]$ gcc -c test.c
[taoge@localhost learn_nm]$ ar rcs libtest.a test.o
[taoge@localhost learn_nm]$ gcc -shared -fPIC -o libtest.so test.o
[taoge@localhost learn_nm]$ ls
libtest.a libtest.so main.c test.c test.h test.o
[taoge@localhost learn_nm]$ nm lib* libtest.a: test.o:
00000000 T print
U puts libtest.so:
000014bc a _DYNAMIC
00001590 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
000014a8 d __CTOR_END__
000014a4 d __CTOR_LIST__
000014b0 d __DTOR_END__
000014ac d __DTOR_LIST__
000004a0 r __FRAME_END__
000014b4 d __JCR_END__
000014b4 d __JCR_LIST__
000015a4 A __bss_start
w __cxa_finalize@@GLIBC_2.1.3
00000440 t __do_global_ctors_aux
00000350 t __do_global_dtors_aux
000014b8 d __dso_handle
w __gmon_start__
00000419 t __i686.get_pc_thunk.bx
000015a4 A _edata
000015ac A _end
00000478 T _fini
000002ec T _init
000015a4 b completed.5963
000015a8 b dtor_idx.5965
000003e0 t frame_dummy
00000420 T print
U puts@@GLIBC_2.0
[taoge@localhost learn_nm]$
可以看到, 我们可以从静态库和动态库中获取到函数名称, 如print函数。
好, 我们再来看看全局变量的情形, 我们把main.c改为:
- #include <stdio.h>
- int add(int x, int y)
- {
- return x + y;
- }
- int aaa;
- int bbb = 1;
- char szTest[] = "good";
- int main()
- {
- int ccc = 2;
- return 0;
- }
#include <stdio.h> int add(int x, int y)
{
return x + y;
} int aaa;
int bbb = 1;
char szTest[] = "good"; int main()
{
int ccc = 2;
return 0;
}
然后用nm分析a.out(注意, 如果只有nm命令, 则默认a.out为其要处理的文件):
- [taoge@localhost learn_nm]$ ls
- main.c
- [taoge@localhost learn_nm]$ gcc main.c
- [taoge@localhost learn_nm]$ ./a.out
- [taoge@localhost learn_nm]$ nm a.out
- 08049538 d _DYNAMIC
- 08049604 d _GLOBAL_OFFSET_TABLE_
- 0804847c R _IO_stdin_used
- w _Jv_RegisterClasses
- 08049528 d __CTOR_END__
- 08049524 d __CTOR_LIST__
- 08049530 D __DTOR_END__
- 0804952c d __DTOR_LIST__
- 08048520 r __FRAME_END__
- 08049534 d __JCR_END__
- 08049534 d __JCR_LIST__
- 08049628 A __bss_start
- 08049618 D __data_start
- 08048430 t __do_global_ctors_aux
- 08048310 t __do_global_dtors_aux
- 08048480 R __dso_handle
- w __gmon_start__
- 0804842a T __i686.get_pc_thunk.bx
- 08049524 d __init_array_end
- 08049524 d __init_array_start
- 080483c0 T __libc_csu_fini
- 080483d0 T __libc_csu_init
- U __libc_start_main@@GLIBC_2.0
- 08049628 A _edata
- 08049634 A _end
- 0804845c T _fini
- 08048478 R _fp_hw
- 08048274 T _init
- 080482e0 T _start
- 08049630 B aaa
- 08048394 T add
- 0804961c D bbb
- 08049628 b completed.5963
- 08049618 W data_start
- 0804962c b dtor_idx.5965
- 08048370 t frame_dummy
- 080483a2 T main
- 08049620 D szTest
- [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
main.c
[taoge@localhost learn_nm]$ gcc main.c
[taoge@localhost learn_nm]$ ./a.out
[taoge@localhost learn_nm]$ nm a.out
08049538 d _DYNAMIC
08049604 d _GLOBAL_OFFSET_TABLE_
0804847c R _IO_stdin_used
w _Jv_RegisterClasses
08049528 d __CTOR_END__
08049524 d __CTOR_LIST__
08049530 D __DTOR_END__
0804952c d __DTOR_LIST__
08048520 r __FRAME_END__
08049534 d __JCR_END__
08049534 d __JCR_LIST__
08049628 A __bss_start
08049618 D __data_start
08048430 t __do_global_ctors_aux
08048310 t __do_global_dtors_aux
08048480 R __dso_handle
w __gmon_start__
0804842a T __i686.get_pc_thunk.bx
08049524 d __init_array_end
08049524 d __init_array_start
080483c0 T __libc_csu_fini
080483d0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
08049628 A _edata
08049634 A _end
0804845c T _fini
08048478 R _fp_hw
08048274 T _init
080482e0 T _start
08049630 B aaa
08048394 T add
0804961c D bbb
08049628 b completed.5963
08049618 W data_start
0804962c b dtor_idx.5965
08048370 t frame_dummy
080483a2 T main
08049620 D szTest
[taoge@localhost learn_nm]$
可以看到, 不仅有add函数, 还有全局变量aaa, bbb和szTest, 要注意, aaa是未初始化的, 所以在Bss段, 而bbb、szTest是初始化了的, 所以在Data段。 值得注意的是, 并没有ccc, 因为ccc是局部变量, nm看不到的。
我们还应该注意到, 在上面看不到"good", 为啥呢? 因为nm是用来看szTest而非"good"的。 别忘了, 我们之前介绍过的strings命令可干这事, 如下:
- [taoge@localhost learn_nm]$ ls
- a.out main.c
- [taoge@localhost learn_nm]$ strings a.out
- /lib/ld-linux.so.2
- __gmon_start__
- libc.so.6
- _IO_stdin_used
- __libc_start_main
- GLIBC_2.0
- PTRh
- [^_]
- good
- [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
a.out main.c
[taoge@localhost learn_nm]$ strings a.out
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
__libc_start_main
GLIBC_2.0
PTRh
[^_]
good
[taoge@localhost learn_nm]$
nm命令主要列出特性文件中的符号信息, 具体更加详细的用法, 请问man, 我就不再过多介绍了。
linux中的nm命令简介的更多相关文章
-
linux中的strings命令简介2
摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 之前我们聊过linux strings的用法和用 ...
-
linux中的strings命令简介
摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 在linux下搞软件开发的朋友, 几乎没有不知道 ...
-
linux中的ldd命令简介
转载自:http://blog.csdn.net/stpeace/article/details/47069215 在linux中, 有些命令是大家通用的, 比如ls, rm, mv, cp等等, 这 ...
-
linux中的strip命令简介------给文件脱衣服
1.去掉-g,等于程序做了--strip-debug2.strip程序,等于程序做了--strip-debug和--strip-symbol 作为一名Linux开发人员, 如果没有听说过strip命令 ...
-
linux中的strip命令简介------给文件脱衣服【转】
转自:http://blog.csdn.net/stpeace/article/details/47090255 版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则 ...
-
linux中的strip命令简介
转载:https://blog.csdn.net/qq_37858386/article/details/78559490 strip:去除,剥去 一.下面是man strip获得到的信息,简 ...
-
Python学习之旅:使用Python实现Linux中的ls命令
一.写在前面 前几天在微信上看到这样一篇文章,链接为:https://mp.weixin.qq.com/s/rl6Sgv3uk_IpoFAx6cWa8w,在这篇文章中,有这样一段话,吸引了我的注意: ...
-
Linux中的历史命令
Linux中的历史命令一般保存在用户 /root/.bash_history history 选项 历史命令保存文件夹 选项 -c:清空历史命令 -w :把缓存中的历史命令写入历 ...
-
关于XShell的常见使用和设置以及Linux中的常见命令.
本文部分转自:http://sundful.iteye.com/blog/704079 和 http://www.vckai.com/p/5 有时候在XShell中操作的一些命令傻傻的分不清这个命令到 ...
随机推荐
-
同时使用python2和Python3
问题:thrift生成的是python2代码,之前使用的是Python3因此需要同时使用两个版本. 方案:将python3的可执行文件重命名为python3(默认为Python),这样使用pyhton ...
-
pagefile.sys and heberfil.sys
dub 删除heberfil.sys大文件的方法 方法1:Windows/system32中的cmd.exe 输入 powercfg -h off,即可关闭休眠功能,同时 Hiberfil.sys ...
-
UI2_UITableViewDelete
// AppDelegate.m // UI2_UITableViewDelete // // Created by zhangxueming on 15/7/14. // Copyright (c) ...
-
[BigData]关于Hadoop学习笔记第四天(PPT总结)(一)
课程安排 Partitioner编程** 自定义排序编程** Combiner编程** 常见的MapReduce算法** ---------------------------加深拓展-------- ...
-
CSS Positioning(定位)
Positioning(定位) CSS定位属性允许你为一个元素定位.它也可以将一个元素放在另一个元素后面,并指定一个元素的内容太大时,应该发生什么. 元素可以使用的顶部,底部,左侧和右侧属性定位.然而 ...
-
Hadoop在Windows环境下的部署[转]
http://blog.csdn.net/ruby97/article/details/7423088 经过一整天的折腾,参考了网上很多资料,我机器上的Hadoop似乎是配置成功了.下面分享一下详细的 ...
-
安卓 ADB常见问题整理
以下都是ADB连接问题,可以通过尝试如下步骤,由简单度排序 1. 插拔下USB连接线 2. 关闭USB模式再打开 3. 执行以下命令 adb kill-server adb start-server ...
-
php简单的文件操作
(1)先要想好要操作哪个文件? (2)确定文件的路径? (3)要有什么文件管理功能? 一.先做一下简单的查看文件功能,文件中的文件和文件夹都显示,但是双击文件夹可以显示下一级子目录,双击"返 ...
-
数据结构学习:KMP模式匹配算法
有关KMP的算法具体的实现网上有很多,不具体阐述.这里附上c的实现. 谈谈我自己的理解.KMP相较于朴素算法,其主要目的是为了使主串中的遍历参数i不回溯,而直接改变目标串中的遍历参数j. 比如说要是目 ...
-
Android版本28使用http请求
Android版本28使用http请求报错not permitted by network security policy android模拟器调试登录的时候报错 CLEARTEXT communic ...