Introduction of nm command in linux


Reference:

  1. Introduction of nm command in linux
  2. nm viewing symbols in dynamic and static libraries for Linux

1. nm function

List the symbol information in. O,. A,. So (not directly applied to main.c, test.h, test.c and other files), including the value, type and name of the symbol. The so-called symbols usually refer to defined functions, global variables, etc.

2. Use

nm [option(s)] [file(s)]

Useful options:

  • -A print the name of the object file in front of each symbol information;
  • -C outputs the symbol name of the demangle;
  • -D. print dynamic symbols;
  • -l use the debugging information in the object file to print the source file and line number;
  • -n sort by address / symbol value;
  • -u print out those undefined symbols.

Common symbol types:

  • A the value of this symbol will not change in future links;
  • B the symbol is placed in the BSS segment, usually those uninitialized global variables;
  • D the symbol is placed in ordinary data segments, usually those initialized global variables;
  • T this symbol is placed in the code segment, usually those global non static functions;
  • U the symbol is undefined and needs to be linked from other object files;
  • W unspecified weak link symbol; If it is defined in other linked object files, use it. Otherwise, use a default value specially specified by the system.

3. Examples

For example:

nm -u hello.o
To display undefined symbols in hello.o, you need to link with other object files.

nm -A /usr/lib/* 2>/dev/null | grep "T memset"
Find out which library file defines the memset function in the / usr/lib / directory.

3.1 test cases

test.h is:

void print();

test.c is:

 #include <stdio.h>
 #include "test.h"
  
 void print()
 {
 	printf("rainy days\n");
 }

main.c is:

 #include "test.h"
  
 int main()
 {
 	print();
 	return 0;
 }

Now look at the effect of the nm command, as follows:

[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]$ 

As mentioned above, nm is useless for such documents. Continue to see if nm can read the target file and executable file:

[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

Let's continue to look at static libraries and dynamic libraries, as follows:

[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

As you can see, we can get the function name from the static library and dynamic library, such as print().

Let's look at the global variables again. We change main.c to:

#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;
}

Then analyze a.out with nm (note that if there is only nm command, a.out is the file to be processed by default):

[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

You can see that not only the add function, but also the global variables aaa, bbb and szTest. Note that aaa is uninitialized, so it is in the Bss section, while bbb and szTest are initialized, so it is in the Data section. It is worth noting that there is no ccc, because ccc is a local variable and nm cannot be seen.

We should also note that we can't see "good" on it. Why? Because nm is used to see szTest, not "good". But the strings command can do this, as follows:

[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

Keywords: Linux

Added by feddie1984 on Sat, 20 Nov 2021 16:09:24 +0200