• Linux - nm命令


    这里的nm命令指的是GNU Linux版本,Ubuntu20.04,是name的缩写。
    nm是一个命令行工具,用来列出object文件、库文件或可执行文件中的符号列表(name list, the symbol table of nlist structures)。
    nm命令的输出结果为三列,symbol virtual address,symbol type和symbol name,即符号虚拟地址,类型和名字。
    显示内容
    举例:
    testnm.c
    #include
    int value;
    static void func()
    {
      printf("value is %d.\n", value);
    }
    int main()
    {
      value = 1;
      func();
      return 0;
    }
    $ gcc -c testnm.c
    $ nm  testnm.o
    0000000000000000 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 T main
                     U printf
    0000000000000004 C value
    用一个字符表示类型,如果是小写字符,则是本地符号(local),如果是大写,则是外部符号(external)。类型符号表示的意义如下。
    类型字符
    含义
    Decription
    A
    全局不可变符号,比如原文件名。
    Global absolute symbol.
    a
    本地不可变符号
    Local absolute symbol.
    B
    全局bss段符号(未初始化的全局或static变量)
    Global bss symbol.
    b
    本地bss段符号
    Local bss symbol.
    D
    全局变量(已初始化的全局或static变量)符号
    Global data symbol.
    d
    本地变量符号
    Local data symbol.
    T
    全局符号,比如全局函数名
    Global text symbol.
    t
    本地符号,比如文件内static函数名
    Local text symbol.
    U
    未定义符号
    Undefined symbol.
    。。。。。。
    用途
    这个命令看起来很酷,但只有合理的使用这个命令,这个命令才有存在的意义。那什么时候使用呢?
    假设你有一个由许多不同object文件组成的可执行文件。现在假设在编译代码的时候,链接器给出了关于一个未解决的符号'temp'的错误。现在,如果代码规模太大,包括很多头文件,要找到代码中的符号'temp'的位置将成为一场噩梦。在这里,这个工具就起到了拯救作用。通过一些选项的配置,这个工具可以找到该符号所在的文件。
    语法:
    $ nm [options(s)]  [file(s)]
    列出参数[file(s)]的文件中的符号,可以给出多个文件,如果没有指定文件名,则默认文件是a.out。
    各个选项的使用:(同一个选项存在短格式和长格式形式则一并列出)
    1,列出object文件里的全局(extern)符号,包括函数和变量:
    nm -g
    nm --extern-only
    举例:
    $ nm -g testnm.o
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 T main
                     U printf
    0000000000000004 C value
    $ nm  testnm.o
    0000000000000000 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 T main
                     U printf
    0000000000000004 C value
    2,列出obj文件内的未定义符号:
    nm -u
    nm --undefined-only 
    举例:
    $ nm -u testnm.o
                     U _GLOBAL_OFFSET_TABLE_
                     U printf
    3,列出obj文件中所有的符号,包括debug所使用的符号,否则默认情况下不显示调试用的符号。
    nm -a
    nm --debug-syms 
    举例:
    $ nm -a testnm.o
    0000000000000000 b .bss
    0000000000000000 n .comment
    0000000000000000 d .data
    0000000000000000 r .eh_frame
    0000000000000000 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 T main
    0000000000000000 r .note.gnu.property
    0000000000000000 n .note.GNU-stack
                     U printf
    0000000000000000 r .rodata
    0000000000000000 a testnm.c
    0000000000000000 t .text
    0000000000000004 C value
    4,列出符号表示,前面显示obj文件名。
    $ nm -A
    $ nm --print-file-name
    这个选项在显示多个多个obj文件的符号时会需要。
    举例:
    $ nm -A testnm.o
    testnm.o:0000000000000000 t func
    testnm.o:                 U _GLOBAL_OFFSET_TABLE_
    testnm.o:0000000000000024 T main
    testnm.o:                 U printf
    testnm.o:0000000000000004 C value
    5,恢复C++符号的名称改变,使其具有更好可读性:
    nm -C 
    nm --demangle
    nm --demangle[=STYLE]
    将编译器级的low-level的符号名,转换成用户可理解的名字类型。可以指定obj文件所使用的名称改编风格,有auto(默认), gnu, lucid, arm, hp, edg, gnu-v3, java 和gnat。
    注意,这个参数对C语言编译出来的obj文件是无效的,上面的C语言的例子,使用-C选项,输出内容并没有变化。
    举例:
    testnm.cpp
    #include
    static int value;
    static void func(int a, int b)
    {
    if(a > b){
       std::cout<<"the value is " << value << std::endl;
    }
    }
    int main()
    {
      value = 3;
      func(2, 1);
      return 0;
    }
    $ g++ -c testnm.cpp
    $ nm testnm.o
                     U __cxa_atexit
                     U __dso_handle
                     U _GLOBAL_OFFSET_TABLE_
    00000000000000cd t _GLOBAL__sub_I_main
    0000000000000058 T main
    0000000000000080 t _Z41__static_initialization_and_destruction_0ii
    0000000000000000 t _ZL4funcii
    0000000000000004 b _ZL5value
                     U _ZNSolsEi
                     U _ZNSolsEPFRSoS_E
                     U _ZNSt8ios_base4InitC1Ev
                     U _ZNSt8ios_base4InitD1Ev
                     U _ZSt4cout
                     U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    0000000000000000 r _ZStL19piecewise_construct
    0000000000000000 b _ZStL8__ioinit
                     U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    $ nm --demangle testnm.o
                     U __cxa_atexit
                     U __dso_handle
                     U _GLOBAL_OFFSET_TABLE_
    00000000000000cd t _GLOBAL__sub_I_main
    0000000000000058 T main
    0000000000000080 t __static_initialization_and_destruction_0(int, int)
    0000000000000000 t func(int, int)
    0000000000000004 b value
                     U std::ostream::operator<<(int)
                     U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
                     U std::ios_base::Init::Init()
                     U std::ios_base::Init::~Init()
                     U std::cout
                     U std::basic_ostream >& std::endl >(std::basic_ostream >&)
    0000000000000000 r std::piecewise_construct
    0000000000000000 b std::__ioinit
                     U std::basic_ostream >& std::operator<< >(std::basic_ostream >&, char const*)
    可以看到上面的例子,除了前面的下划线去掉了,C++的函数名字也变得可读性更好。不同的编译器使用不同的名称改变风格(mangling styles),可以使用上面提到的改变风格的选项来选择一种适合当前编译器。
    6,显示动态链接的符号。
    nm -D 
    nm --dynamic 
    举例:
    $ gcc -o testnm testnm.c
    $ ldd testnm
        linux-vdso.so.1 (0x00007ffd7dff0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff2c819a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff2c83a3000)
    $ nm -D testnm
                     w __cxa_finalize
                     w __gmon_start__
                     w _ITM_deregisterTMCloneTable
                     w _ITM_registerTMCloneTable
                     U __libc_start_main
                     U printf
    $ g++ -o testnmplus testnm.cpp
    $ ldd testnmplus
        linux-vdso.so.1 (0x00007ffd82bd0000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff7716a4000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff7714b2000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff771363000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff77189d000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff771348000)
    $ nm -D testnmplus
                     U __cxa_atexit
                     w __cxa_finalize
                     w __gmon_start__
                     w _ITM_deregisterTMCloneTable
                     w _ITM_registerTMCloneTable
                     U __libc_start_main
                     U _ZNSolsEi
                     U _ZNSolsEPFRSoS_E
                     U _ZNSt8ios_base4InitC1Ev
                     U _ZNSt8ios_base4InitD1Ev
    0000000000004040 B _ZSt4cout
                     U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
                     U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    这里编出来的obj文件,没有动态链接符号,而编出的可执行文件里才有。
    这些动态链接的符号,只有在运行时(run time)才会解析。
    7,更改输出内容的格式。
    nm -f
    nm --format=FORMAT
    可选的输出格式为bsd,sysv或posix,默认是bsd模式。
    举例:
    $ nm -f posix testnm.o
    func t 0 24
    _GLOBAL_OFFSET_TABLE_ U         
    main T 24 23
    printf U         
    value C 4 4
    $ nm --format posix testnm.o
    func t 0 24
    _GLOBAL_OFFSET_TABLE_ U         
    main T 24 23
    printf U         
    value C 4 4
    $ nm --format=posix testnm.o
    func t 0 24
    _GLOBAL_OFFSET_TABLE_ U         
    main T 24 23
    printf U         
    value C 4 4
    $ nm --format=sysv testnm.o
    Symbols from testnm.o:
    Name                  Value           Class        Type         Size             Line  Section
    func                |0000000000000000|   t  |              FUNC|0000000000000024|     |.text
    _GLOBAL_OFFSET_TABLE_|                |   U  |            NOTYPE|                |     |*UND*
    main                |0000000000000024|   T  |              FUNC|0000000000000023|     |.text
    printf              |                |   U  |            NOTYPE|                |     |*UND*
    value               |0000000000000004|   C  |            OBJECT|0000000000000004|     |*COM*
    8,使用排序选项。
    默认情况下,符号列表根据字母顺序进行排序,但你可以选择根据地址进行排序。
    nm -n 
    nm --numeric-sort 
    举例:
    $ nm  -n  testnm.o
                     U _GLOBAL_OFFSET_TABLE_
                     U printf
    0000000000000000 t func
    0000000000000004 C value
    0000000000000024 T main
    默认使用的是字母排序,也可以不使用排序功能。
    nm -p 
    nm --no-sort
    举例:
    $ nm  -p  testnm.o
    0000000000000000 t func
    0000000000000004 C value
                     U _GLOBAL_OFFSET_TABLE_
                     U printf
    0000000000000024 T main
    $ nm  testnm.o
    0000000000000000 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 T main
                     U printf
    0000000000000004 C value
    还可以按照符号占用空间的大小排序。
    nm --size-sort 
    如果想使用相反的顺序,使用-r选项。
    nm -r
    nm --reverse-sort
    举例:
    $ nm -n testnm.o
                     U _GLOBAL_OFFSET_TABLE_
                     U printf
    0000000000000000 t func
    0000000000000004 C value
    0000000000000024 T main
    $ nm -rn testnm.o
    0000000000000024 T main
    0000000000000004 C value
    0000000000000000 t func
                     U printf
                     U _GLOBAL_OFFSET_TABLE_
    9,只显示未定义的符号。
    nm -u
    nm --undefined-only
    举例:
    $ nm -u testnm.o
                     U _GLOBAL_OFFSET_TABLE_
                     U printf
    如果在一个可执行文件中发现未定义的符号,可能是这个符号存在于动态链接库中(shared libraries)。
    10,只显示已定义的符号。
    nm --defined-only
    举例:
    $ nm --defined-only testnm.o
    0000000000000000 t func
    0000000000000024 T main
    0000000000000004 C value
    11,显示符号占用空间的大小
    nm -S
    nm --print-size
    举例:
    $ nm  testnm.o
    0000000000000000 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 T main
                     U printf
    0000000000000004 C value
    $ nm -S testnm.o
    0000000000000000 0000000000000024 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 0000000000000023 T main
                     U printf
    0000000000000004 0000000000000004 C value
    12,使用文件来指定选项。
    nm命令还有一个功能,可以从一个文件里读取命令行的选项。
    举例:
    $ cat file
    -S testnm.o
    $ nm @file
    0000000000000000 0000000000000024 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 0000000000000023 T main
                     U printf
    0000000000000004 0000000000000004 C value
    $ nm -S testnm.o
    0000000000000000 0000000000000024 t func
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 0000000000000023 T main
                     U printf
    0000000000000004 0000000000000004 C value
    13,使用案例
    在当前文件夹的obj文件中,找寻包含func字符串的符号名称。
    $ nm  -A ./*.o | grep func
    ./hello2.o:0000000000000000 T func_1
    ./hello3.o:0000000000000000 T func_2
    ./hello4.o:0000000000000000 T func_3
    ./main.o:                   U func
    ./reloc.o:                  U func
    ./reloc.o:0000000000000000  T func1
    ./test1.o:0000000000000000  T func
    ./test.o:                   U func
    上面介绍的各个功能选项可以组合使用来满足自己的需求。比如:
    $ nm -g -S testnm.o
    $ nm -gS testnm.o
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000024 0000000000000023 T main
                     U printf
    0000000000000004 0000000000000004 C value
    另外,输出内容里的符号地址,其基数(radix)是可变的,默认是16进制(hexadecimal),使用的参数是:  
    -t, --radix=RADIX      // Use RADIX for printing symbol values
    备注1:
    可以在linux源码中查询到符号列表条目的类型定义nlist结构体:
    struct nlist {
    union {
         char *n_name;
         struct nlist *n_next;
         long n_strx;
    } n_un;
    unsigned char n_type;
    char n_other;
    short n_desc;
    unsigned long n_value;
    };
    备注2:
    nm命令的简单help信息:
    $ nm --help
    Usage: nm [option(s)] [file(s)]
    List symbols in [file(s)] (a.out by default).
    The options are:
      -a, --debug-syms       Display debugger-only symbols
      -A, --print-file-name  Print name of the input file before every symbol
      -B                     Same as --format=bsd
      -C, --demangle[=STYLE] Decode low-level symbol names into user-level names
                              The STYLE, if specified, can be `auto' (the default),
                              `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'
                              or `gnat'
          --no-demangle      Do not demangle low-level symbol names
          --recurse-limit    Enable a demangling recursion limit.  This is the default.
          --no-recurse-limit Disable a demangling recursion limit.
      -D, --dynamic          Display dynamic symbols instead of normal symbols
          --defined-only     Display only defined symbols
      -e                     (ignored)
      -f, --format=FORMAT    Use the output format FORMAT.  FORMAT can be `bsd',
                               `sysv' or `posix'.  The default is `bsd'
      -g, --extern-only      Display only external symbols
      -l, --line-numbers     Use debugging information to find a filename and
                               line number for each symbol
      -n, --numeric-sort     Sort symbols numerically by address
      -o                     Same as -A
      -p, --no-sort          Do not sort the symbols
      -P, --portability      Same as --format=posix
      -r, --reverse-sort     Reverse the sense of the sort
          --plugin NAME      Load the specified plugin
      -S, --print-size       Print size of defined symbols
      -s, --print-armap      Include index for symbols from archive members
          --size-sort        Sort symbols by size
          --special-syms     Include special symbols in the output
          --synthetic        Display synthetic symbols as well
      -t, --radix=RADIX      Use RADIX for printing symbol values
          --target=BFDNAME   Specify the target object format as BFDNAME
      -u, --undefined-only   Display only undefined symbols
          --with-symbol-versions  Display version strings after symbol names
      -X 32_64               (ignored)
      @FILE                  Read options from FILE
      -h, --help             Display this information
      -V, --version          Display this program's version number
    nm: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 srec symbolsrec verilog tekhex binary ihex plugin
    Report bugs to .
    备注3:
    Ubuntu中的manual中关于符号意义的解释:
           •   The symbol type.  At least the following types are used; others are, as well, depending on the object file format.  If lowercase, the symbol is usually local; if uppercase, the symbol is
               global (external).  There are however a few lowercase symbols that are shown for special global symbols ("u", "v" and "w").
               "A" The symbol's value is absolute, and will not be changed by further linking.
               "B"
               "b" The symbol is in the BSS data section.  This section typically contains zero-initialized or uninitialized data, although the exact behavior is system dependent.
               "C" The symbol is common.  Common symbols are uninitialized data.  When linking, multiple common symbols may appear with the same name.  If the symbol is defined anywhere, the common
                   symbols are treated as undefined references.
               "D"
               "d" The symbol is in the initialized data section.
               "G"
               "g" The symbol is in an initialized data section for small objects.  Some object file formats permit more efficient access to small data objects, such as a global int variable as opposed
                   to a large global array.
               "i" For PE format files this indicates that the symbol is in a section specific to the implementation of DLLs.  For ELF format files this indicates that the symbol is an indirect
                   function.  This is a GNU extension to the standard set of ELF symbol types.  It indicates a symbol which if referenced by a relocation does not evaluate to its address, but instead
                   must be invoked at runtime.  The runtime execution will then return the value to be used in the relocation.
               "I" The symbol is an indirect reference to another symbol.
               "N" The symbol is a debugging symbol.
               "n" The symbol is in the read-only data section.
               "p" The symbol is in a stack unwind section.
               "R"
               "r" The symbol is in a read only data section.
               "S"
               "s" The symbol is in an uninitialized or zero-initialized data section for small objects.
               "T"
               "t" The symbol is in the text (code) section.
               "U" The symbol is undefined.
               "u" The symbol is a unique global symbol.  This is a GNU extension to the standard set of ELF symbol bindings.  For such a symbol the dynamic linker will make sure that in the entire
                   process there is just one symbol with this name and type in use.
               "V"
               "v" The symbol is a weak object.  When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error.  When a weak undefined symbol is
                   linked and the symbol is not defined, the value of the weak symbol becomes zero with no error.  On some systems, uppercase indicates that a default value has been specified.
               "W"
               "w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.  When a weak defined symbol is linked with a normal defined symbol, the normal defined
                   symbol is used with no error.  When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error.
                   On some systems, uppercase indicates that a default value has been specified.
               "-" The symbol is a stabs symbol in an a.out object file.  In this case, the next values printed are the stabs other field, the stabs desc field, and the stab type.  Stabs symbols are
                   used to hold debugging information.
               "?" The symbol type is unknown, or object file format specific.
    备注4:
    在Ubuntu里,使用PC平台的nm命令,也可以解析cross toolchain编译的程序。
    $ cat testuart.c
    include
    #include
    #include
    int main()
    {
    int fd;
    fd = open("/dev/ttyS3", O_RDWR | O_NOCTTY | O_CLOEXEC);
    printf("fd is %d.\n", fd);
    return 0;
    }
    使用工具链进行编译:
    X86:
    $ gcc -o testuartgcc testuart.c
    ARM:
    $ /opt/poky/SDK220804V0/sysroots/x86_64-pokyXXXsdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++ -o testuartarm testuart.c --sysroot=/opt/poky/SDK220804V0/sysroots/cortexa7t2hf-neon-poky-linux-gnueabi/ -march=armv7ve -marm -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7
    MIPS:
    $ ~/x2000br/buildroot/buildroot/output/host/usr/bin/mipsel-linux-gcc -o testuartmips testuart.c
    得到可执行文件:
    $ file testuartgcc
    testuartgcc: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7502376cbab0f5ea2a13197d89a126dffdc32876, for GNU/Linux 3.2.0, not stripped
    $ file testuartarm
    testuartarm: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=aeea22788a340f6862e60c02021fc5718dbb1d12, for GNU/Linux 3.2.0, with debug_info, not stripped
    $ file testuartmips
    testuartmips: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-mipsn8.so.1, for GNU/Linux 5.4.0, not stripped
    $ which nm
    /usr/bin/nm
    $ ll /usr/bin/nm
    lrwxrwxrwx 1 root root 19 10月 20  2021 /usr/bin/nm -> x86_64-linux-gnu-nm*
    使用X86平台, mips toolchain和arm toolchain的nm命令分别读取x86程序的符号列表:
    ARM不能读,其他两个结果一样。
    $ ~/x2000br/buildroot/buildroot/output/host/usr/bin/mipsel-linux-nm -g -n testuartgcc
                     w __cxa_finalize@@GLIBC_2.2.5
                     w __gmon_start__
                     w _ITM_deregisterTMCloneTable
                     w _ITM_registerTMCloneTable
                     U __libc_start_main@@GLIBC_2.2.5
                     U open@@GLIBC_2.2.5
                     U printf@@GLIBC_2.2.5
    0000000000001080 T _start
    0000000000001169 T main
    00000000000011b0 T __libc_csu_init
    0000000000001220 T __libc_csu_fini
    0000000000001228 T _fini
    0000000000002000 R _IO_stdin_used
    0000000000004000 D __data_start
    0000000000004000 W data_start
    0000000000004008 D __dso_handle
    0000000000004010 B __bss_start
    0000000000004010 D _edata
    0000000000004010 D __TMC_END__
    0000000000004018 B _end
    $ nm -g -n testuartgcc
                     w __cxa_finalize@@GLIBC_2.2.5
                     w __gmon_start__
                     w _ITM_deregisterTMCloneTable
                     w _ITM_registerTMCloneTable
                     U __libc_start_main@@GLIBC_2.2.5
                     U open@@GLIBC_2.2.5
                     U printf@@GLIBC_2.2.5
    0000000000001080 T _start
    0000000000001169 T main
    00000000000011b0 T __libc_csu_init
    0000000000001220 T __libc_csu_fini
    0000000000001228 T _fini
    0000000000002000 R _IO_stdin_used
    0000000000004000 D __data_start
    0000000000004000 W data_start
    0000000000004008 D __dso_handle
    0000000000004010 B __bss_start
    0000000000004010 D _edata
    0000000000004010 D __TMC_END__
    0000000000004018 B _end
    $ /opt/poky/SDK220804V0/sysroots/x86_64-pokyXXXsdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-nm -g -n testuartgcc
    /opt/poky/SDK220804V0/sysroots/x86_64-pokyXXXsdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-nm: testuartgcc: file format not recognized
    使用X86平台, mips toolchain和arm toolchain的nm命令分别读取mips程序的符号列表:
    都可以读,内容一样。
    $ nm -g -n testuartmips
             w __cxa_finalize@GLIBC_2.2
             w __gmon_start__
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             U __libc_start_main@GLIBC_2.34
             U open@GLIBC_2.0
             U printf@GLIBC_2.0
             U __stack_chk_fail@GLIBC_2.4
             U __stack_chk_guard@GLIBC_2.4
    000005d0 T _init
    00000660 T _ftext
    00000660 T __start
    00000840 T main
    000009b0 T _fini
    00000a00 R _IO_stdin_used
    00011000 D __data_start
    00011000 W data_start
    00011000 D _fdata
    00011010 D __RLD_MAP
    00011074 B __bss_start
    00011074 G _edata
    00011074 B _fbss
    00011090 B _end
    $ ~/x2000br/buildroot/buildroot/output/host/usr/bin/mipsel-linux-nm -g -n testuartmips
             w __cxa_finalize@GLIBC_2.2
             w __gmon_start__
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             U __libc_start_main@GLIBC_2.34
             U open@GLIBC_2.0
             U printf@GLIBC_2.0
             U __stack_chk_fail@GLIBC_2.4
             U __stack_chk_guard@GLIBC_2.4
    000005d0 T _init
    00000660 T _ftext
    00000660 T __start
    00000840 T main
    000009b0 T _fini
    00000a00 R _IO_stdin_used
    00011000 D __data_start
    00011000 W data_start
    00011000 D _fdata
    00011010 D __RLD_MAP
    00011074 B __bss_start
    00011074 D _edata
    00011074 B _fbss
    00011090 B _end
    $ /opt/poky/SDK220804V0/sysroots/x86_64-pokyXXXsdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-nm -g -n testuartmips
             w __cxa_finalize@GLIBC_2.2
             w __gmon_start__
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             U __libc_start_main@GLIBC_2.34
             U open@GLIBC_2.0
             U printf@GLIBC_2.0
             U __stack_chk_fail@GLIBC_2.4
             U __stack_chk_guard@GLIBC_2.4
    000005d0 T _init
    00000660 T _ftext
    00000660 T __start
    00000840 T main
    000009b0 T _fini
    00000a00 R _IO_stdin_used
    00011000 D __data_start
    00011000 W data_start
    00011000 D _fdata
    00011010 D __RLD_MAP
    00011074 B __bss_start
    00011074 D _edata
    00011074 B _fbss
    00011090 B _end
    使用X86平台, mips toolchain和arm toolchain的nm命令分别读取arm程序的符号列表:
    $ nm -g -n testuartarm
             U abort@@GLIBC_2.4
             U __aeabi_unwind_cpp_pr1@@GCC_3.5
             w __cxa_finalize@@GLIBC_2.4
             w __gmon_start__
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             U __libc_start_main@@GLIBC_2.34
             U open@@GLIBC_2.4
             U printf@@GLIBC_2.4
    00000444 T _init
    000004ad T _start
    000005a8 T main
    00000600 T _fini
    00000608 R _IO_stdin_used
    00011038 D __data_start
    00011038 W data_start
    0001103c D __dso_handle
    00011040 B __bss_start
    00011040 B __bss_start__
    00011040 D _edata
    00011040 D __TMC_END__
    00011044 B __bss_end__
    00011044 B _bss_end__
    00011044 B __end__
    00011044 B _end
    $ ~/x2000br/buildroot/buildroot/output/host/usr/bin/mipsel-linux-nm -g -n testuartarm
             U abort@@GLIBC_2.4
             U __aeabi_unwind_cpp_pr1@@GCC_3.5
             w __cxa_finalize@@GLIBC_2.4
             w __gmon_start__
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             U __libc_start_main@@GLIBC_2.34
             U open@@GLIBC_2.4
             U printf@@GLIBC_2.4
    00000444 T _init
    000004ad T _start
    000005a8 T main
    00000600 T _fini
    00000608 R _IO_stdin_used
    00011038 D __data_start
    00011038 W data_start
    0001103c D __dso_handle
    00011040 B __bss_start
    00011040 B __bss_start__
    00011040 D _edata
    00011040 D __TMC_END__
    00011044 B __bss_end__
    00011044 B _bss_end__
    00011044 B __end__
    00011044 B _end
    $ /opt/poky/SDK220804V0/sysroots/x86_64-pokyXXXsdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-nm -g -n testuartarm
             U abort@@GLIBC_2.4
             U __aeabi_unwind_cpp_pr1@@GCC_3.5
             w __cxa_finalize@@GLIBC_2.4
             w __gmon_start__
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             U __libc_start_main@@GLIBC_2.34
             U open@@GLIBC_2.4
             U printf@@GLIBC_2.4
    00000444 T _init
    000004ac T _start
    000005a8 T main
    00000600 T _fini
    00000608 R _IO_stdin_used
    00011038 D __data_start
    00011038 W data_start
    0001103c D __dso_handle
    00011040 B __bss_start
    00011040 B __bss_start__
    00011040 D _edata
    00011040 D __TMC_END__
    00011044 B __bss_end__
    00011044 B _bss_end__
    00011044 B __end__
    00011044 B _end
    结论就是,对于nm命令,不一定要使用cross-toolchain的版本,用Ubuntu里自带的nm也一样用,结果一样。如果有问题,再换成toolchain里面的nm命令。
    因为nm查询的是符号名称,这部分功能可能和芯片类型关系不大,各个不同的toolchain,编译出来的格式是类似的,大致上是使用的相同的框架来管理符号。
    参考:
  • 相关阅读:
    c++计时器
    java对象以及引用方式
    深入理解Java虚拟机之【虚拟机栈】
    Python结合文件名称将多个文件复制到不同路径下
    RISC-V入门(基础概念+汇编部分) 基于 汪辰老师的视频笔记
    在C代码中找到栈顶的位置并访问栈空间
    make命令常用选项 + gcc 常用选项
    (二)k8-集群创建
    【论文阅读笔记】Revisiting RCAN: Improved Training for Image Super-Resolution
    技术应用:使用 FastJSON 作为 RedisTemplate 序列化器:禁用循环引用检测和类名序列化
  • 原文地址:https://blog.csdn.net/guoqx/article/details/127828038