Reference:
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