How to Use the Command 'nm' (with examples)
The nm
command is a versatile tool used primarily by developers and system programmers to inspect the symbol table of object files. It is particularly useful when debugging or trying to understand the inner workings of compiled programs. The nm
command reveals valuable information about the symbols—such as functions and variables—contained in object files, libraries, and executable files. This information can be utilized to track down errors, optimize performance, or simply understand the components of a binary.
List Global (Extern) Functions in a File
Code:
nm -g path/to/file.o
Motivation:
When working with large codebases or projects that involve multiple programmers, it often becomes necessary to identify and understand the external functions available within a specific object file. External functions are those defined within a file and made available to other object files during linking. By listing these global symbols, developers can gain insight into the functionality exposed by a particular module or library, aiding in integration efforts and code reviews.
Explanation:
nm
: The command used to list symbols from object files.-g
: The flag instructsnm
to filter symbols to show only global (external) functions, typically denoted by the symbol type ‘T’.path/to/file.o
: The path to the object file whose global symbols you wish to inspect. This file is the output of the compiler during the intermediary steps of building a program.
Example Output:
00000000 T _start
00000011 T main
00000029 T add_numbers
In this output, we observe several global symbols, each prefixed with the symbol type ‘T’, indicating these are text (code) symbols or functions exposed for external linkage.
List Only Undefined Symbols in a File
Code:
nm -u path/to/file.o
Motivation:
During debugging, identifying unresolved or undefined symbols within an object file is a critical task. Undefined symbols can lead to linking errors, causing the build process to fail. The -u
option in nm
is particularly helpful in pinpointing exactly which symbols need resolutions, aiding developers in identifying missing dependencies or incomplete code.
Explanation:
nm
: The command that lists symbols from object files.-u
: The flag directsnm
to list only the undefined symbols. Undefined symbols in an object file are those that are declared but not defined within that file. The linker resolves these symbols by combining files that contain definitions.path/to/file.o
: This specifies the object file being queried.
Example Output:
U printf
U external_function
In the output, the ‘U’ preceding each symbol indicates these are undefined symbols, such as printf
and external_function
, which must be resolved for successful program linking.
List All Symbols, Even Debugging Symbols
Code:
nm -a path/to/file.o
Motivation:
While troubleshooting complex systems or performing in-depth code analysis, being able to view all available symbols in an object file, including debugging symbols, is immensely beneficial. Debugging symbols provide additional context—for example, variable names and their lifetimes—which can significantly aid during the debugging process, especially in optimizing, maintaining, or altering legacy code.
Explanation:
nm
: The command for listing symbols.-a
: This option tellsnm
to include all symbols, not just those typically visible in the default list. This includes local, global, and debugging symbols.path/to/file.o
: The location of the object file under examination.
Example Output:
00000000 t local_function
00000000 T _start
00000011 T main
00000029 T add_numbers
0000002d d debug_info
00000000 B buffer
00000000 D initialized_data
The sample output shows symbols with different types: lowercase symbols like t
for local symbols, uppercase for global symbols like T
, D
, and B
for data locations, and a mixture of user-visible functions and debugging information.
Demangle C++ Symbols (Make Them Readable)
Code:
nm --demangle path/to/file.o
Motivation:
C++ names are often mangled during the compilation process, transforming them into complicated symbols that maintain uniqueness during linking. This mangling makes symbols quite unreadable. For developers, especially in C++ projects, demangle
is essential for translating these names back into human-readable form, which significantly eases code analysis, debugging, and understanding flow.
Explanation:
nm
: The command to list symbols.--demangle
or-C
: This argument suggests thatnm
should attempt to demangle C++ symbols to better comprehend them by transforming them back into their original source code form.path/to/file.o
: The path to the object file being inspected.
Example Output:
00000000 T _ZN3Foo3BarEv
00000011 T main
00000029 T _ZN3Foo4BazEi
The output before demangling would show C++ symbols as _ZN3Foo3BarEv
etc., but with demangling, these symbols are rendered into readable signatures like Foo::Bar()
, offering immediate clarity into their purpose and scope.
Conclusion
The nm
command is a powerful utility that provides detailed insights into the symbols present in object files. Whether you’re tracking down unresolved functions or deciphering complex C++ symbols, nm
offers a suite of options to help diagnose and understand compiled binaries. From global symbol listing to demangling C++ names, mastering these use cases can enhance debugging, linking, and cross-team software integration efforts.