Nm (Unix)

nm命令存在于多数后出版本的Unix及类似的操作系统中。nm被用来检查二进制文件（包括库，编译后的目标模块，共享目标文件，和独立可执行文件）并显示这些文件的内容，或存储在其中的元信息，特别是符号表。来自nm的输出区分各种符号类型。例如，在一个目标文件所提供的函数和它所需要的函数之间是有区别的。nm被用作调试的辅助工具，帮助解决名字冲突和C++名称修饰引起的问题，和验证工具链的其他部分。

GNU计划在GNU Binutils包中提供了一个nm的实现。objdump -t和readelf -s也可以查看目标文件的符号表。

nm输出样例
下面的例子展示了变量和函数在全局、局部、外部、静态、自动和初始化的不同情况下的不同符号类型。
/*
 * 文件名: test.c
 * 对于C代码如下编译： 
 * gcc -c test.c
 *
 * 对于C++代码如下编译：
 * g++ -c test.cpp
 */

int global_var;
int global_var_init = 26;

static int static_var;
static int static_var_init = 25;

extern int extern_var;
extern int extern_function(int);

static int static_function(int x, int y)
{
	int local_automatic_var;

	local_automatic_var = x + y;
	return local_automatic_var;
}

int global_function(int p)
{
	static int local_static_var;
	static int local_static_var_init=5;
	
	local_static_var = static_function(local_static_var_init, p);	
	return local_static_var;
}

int main(int argc, char** argv)
{
	static_var = 1;

	global_var = global_function(2);
	extern_var = extern_function(3);
	return 0;
}

#ifdef __cplusplus
extern "C"
#endif
void non_mangled_function(void)
{
	// I do nothing
}

如果上述代码使用了gcc C编译器来编译，nm命令的输出将是如下这样：
$ nm test.o
                 U extern_function
                 U extern_var
000000000000001a T global_function
                 U _GLOBAL_OFFSET_TABLE_
0000000000000004 C global_var
0000000000000000 D global_var_init
0000000000000004 b local_static_var.1970
0000000000000008 d local_static_var_init.1971
000000000000004c T main
0000000000000045 T non_mangled_function
0000000000000000 t static_function
0000000000000000 b static_var
0000000000000004 d static_var_init
默认按符号字母序排序，其中，大写字母表示全局性，小写字母表示局部性；U表示此符号未定义，C表示此符号是公共的，T/t表示此符号在正文（代码）段中，D/d的表示此符号在初始化数据段中，B/b表示此符号在BSS数据段中。

在使用了C++编译器时，输出是不同的：
$ nm test.o
                 U extern_var
                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 B global_var
0000000000000000 D global_var_init
000000000000004c T main
0000000000000045 T non_mangled_function
                 U _Z15extern_functioni
000000000000001a T _Z15global_functioni
0000000000000004 b _ZL10static_var
0000000000000000 t _ZL15static_functionii
0000000000000004 d _ZL15static_var_init
0000000000000008 b _ZZ15global_functioniE16local_static_var
0000000000000008 d _ZZ15global_functioniE21local_static_var_init

在二者输出之间的不同还展示了通过在C++代码中使用extern "C"解决名称修饰问题的一个例子。

参见
objdump
readelf

外部链接

Unix编程工具
Unix SUS2008实用工具