nm命令如何查看目标文件符号表

概述

  • 在Linux环境下,nm 是一个用来查看目标文件(如可执行文件、动态库或静态库)符号表的工具。
  • 使用nm命令可以很方便的查看可执行程序中有哪些函数以及动态库中有哪些导出函数。

nm命令简述

打印结果含义

  • 先使用nm命令查看一个可执行程序,分析下结果是什么意思
  •   [root@dev nmparse]# nm res
      00000000004004e8 T _init
      0000000000600df8 t __init_array_end
      0000000000600df0 t __init_array_start
      00000000004006d8 R _IO_stdin_used
                       w _ITM_deregisterTMCloneTable
                       w _ITM_registerTMCloneTable
      00000000004006c0 T __libc_csu_fini
      0000000000400650 T __libc_csu_init
                       U __libc_start_main@@GLIBC_2.2.5
      0000000000400621 T main
                       U myMathAdd
      00000000004005a0 t register_tm_clones
      0000000000400530 T _start
      0000000000601028 D __TMC_END__
      0000000000400616 T _Z6myfuncv
    
  • 可以看到有三列数据,第一列是地址,第二列是符号类型标识符,第三列是符号名称
    • 地址:即符号在内存中的地址
    • 符号类型标识符
      • T:全局函数
      • B: 静态变量
      • D: 未初始化的数据段
      • U: 外部引用。比如调用的动态库函数
    • 符号名称: 它代表了具体的函数名、变量名或者标签等

nm参数

  • 可以通过nm --help命令查看nm的参数都有哪些,这里重点介绍常用的几个
  • nm -g: 只显示全局符号,一般用来查看可执行程序中都有哪些函数
  • nm -D: 只显示动态符号, 一般用来查看动态库中导出了哪些函数
  • nm -C: 对C++等语言产生的低级符号名称进行解码,显示为可读的形式

查看动态库的导出函数

  • 我们写两个函数,然后生成一个动态库

实现动态库

  • 文件内容
    • myMath.h
    •   #ifndef __MY_MATH_H__
        #define __MY_MATH_H__
        int myMathAdd(int num1, int num2);
        int myMathMinus(int num1, int num2);
        #endif
      
    • myMath.cpp
    •   #include "myMath.h"
        int myMathAdd(int num1, int num2){
                return num1 + num2;
        }
      
        int myMathMinus(int num1, int num2){
                return num1 - num2;
        }
      
  • 生成动态库
    •   g++ -c myMath.cpp -o myMath.o -fPIC
        g++ -shared -o libmyMath.so myMath.o
      

使用nm -D命令查看动态库的导出函数

  •   nm -D libmyMath.so
    
  • 可以看到我们写的那两个函数 myMathAddmyMathMinus
  •   [root@dev nmparse]# nm -D libmyMath.so
      0000000000201020 B __bss_start
                       w __cxa_finalize
      0000000000201020 D _edata
      0000000000201028 B _end
                       w __gmon_start__
                       w _ITM_deregisterTMCloneTable
                       w _ITM_registerTMCloneTable
      00000000000005bd T _Z11myMathMinusii
      00000000000005a9 T _Z9myMathAddii
    
  • 但是这两个函数前后都出现了特殊符号,这是因为默认使用的C++编译器,C++是支持重载的,因此在编译出来的库,导出函数不仅包含函数名,还包含参数个数个类型。因此会出现特殊符号。
  • 可以加一个 -C 参数,把特殊符号转换为可读符号。可以看到导出函数包含了参数个数和参数类型
  •   [root@dev nmparse]# nm -D -C libmyMath.so
      0000000000201020 B __bss_start
                       w __cxa_finalize
      0000000000201020 D _edata
      0000000000201028 B _end
                       w __gmon_start__
                       w _ITM_deregisterTMCloneTable
                       w _ITM_registerTMCloneTable
      00000000000005ed T myMathMinus(int, int)
      00000000000005d9 T myMathAdd(int, int)
    
  • 如果不想导出函数的参数个数和类型,编译动态库时可指定使用C编译器编译, 修改myMath.h如下
  •   #ifndef __MY_MATH_H__
      #define __MY_MATH_H__
      extern "C" {
          int myMathAdd(int num1, int num2);
          int myMathMinus(int num1, int num2);
      }
      #endif
    
  • 重新编译动态库后在使用nm -D命令查看,可以看到导出函数只有函数名了。
  •   [root@dev nmparse]# nm -D libmyMath.so
      0000000000201020 B __bss_start
                       w __cxa_finalize
      0000000000201020 D _edata
      0000000000201028 B _end
                       w __gmon_start__
                       w _ITM_deregisterTMCloneTable
                       w _ITM_registerTMCloneTable
      00000000000005c9 T myMathAdd
      00000000000005dd T myMathMinus
    

查看可执行程序中的函数

生成可执行程序

  • 写一个可执行程序,链接上面写的那个库文件
  • 文件内容
    •   #include "myMath.h"
      
        int dataTemp = 0;
      
        int myfunc(){
                return 0;
        }
      
        int main(){
                int sum = 0;
                sum = myMathAdd(10, 20);
                return 0;
        }
      
      
  • 生成可执行程序并链接动态库
    •   gcc main.cpp -L. -lmyMath -o res
      

使用nm -g命令查看可执行程序中的函数

  •   nm -g res
    
  • 可以看到自己实现的函数myfunc, 全局变量dataTemp以及引用的外部函数myMathAdd
  •   [root@dev nmparse]# nm -g -C res
      0000000000601024 B __bss_start
      0000000000601020 D __data_start
      0000000000601020 W data_start
      0000000000601028 B dataTemp
      0000000000400560 T _dl_relocate_static_pie
      00000000004006e0 R __dso_handle
      0000000000601024 D _edata
      0000000000601030 B _end
      00000000004006c8 T _fini
                       w __gmon_start__
      00000000004004e8 T _init
      00000000004006d8 R _IO_stdin_used
                       w _ITM_deregisterTMCloneTable
                       w _ITM_registerTMCloneTable
      00000000004006c0 T __libc_csu_fini
      0000000000400650 T __libc_csu_init
                       U __libc_start_main@@GLIBC_2.2.5
      0000000000400621 T main
                       U myMathAdd
      0000000000400530 T _start
      0000000000601028 D __TMC_END__
      0000000000400616 T myfunc()
    
  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值