nm
List symbols from object files and executables
By CMD Script Team · 4 min read · Last updated
nm [OPTIONS] FILE...Options
| Flag | Description |
|---|---|
-D | Display dynamic symbols instead of normal symbols; needed for stripped shared libraries and dynamic executables |
-u | Show only undefined symbols — ones referenced but not defined in this file |
-C | Demangle C++ symbol names into human-readable form (e.g. foo::bar(int) instead of _ZN3foo3barEi) |
-g | Show only external (global) symbols, hiding local/static ones |
--size-sort | Sort output by symbol size instead of by name or address |
-A | Prefix each line with the filename, useful when passing multiple files at once |
Distribution compatibility
- Ubuntu
- Debian
- Fedora
- Arch
- macOS (via Xcode Command Line Tools, part of llvm binutils)
What it does
nm lists the symbol table of an object file, static library, or executable — every
function and global/static variable it defines, references, or exports, along with each
symbol's type and (when available) address. It's the standard way to inspect exactly
what names a compiled file provides and what it still needs, which makes it the primary
tool for diagnosing linker errors like "undefined reference to foo".
Beginner examples
nm myfile.o— list every symbol defined or referenced in an object filenm -u myfile.o— show only symbols this file references but doesn't define (undefined symbols)nm -C myprogram— demangle C++ symbol names into readable formnm -D libexample.so— list dynamic symbols exported by a shared librarynm -g myfile.o— show only external/global symbols, hiding local statics
nm -u myfile.o
Advanced examples
- Track down which library defines a missing symbol during a link failure:
nm -D /usr/lib/x86_64-linux-gnu/*.so 2>/dev/null | grep my_missing_symbol - Compare defined vs. undefined symbols across a set of object files before linking:
for f in *.o; do echo "== $f =="; nm -u "$f"; done - Sort symbols by size to find unusually large functions or data objects:
nm --size-sort -C myprogram - Confirm a shared library actually exports the symbols a program expects at runtime:
nm -D --defined-only libexample.so
nm -C -u myapp.o | grep " U "
Common mistakes
- Running plain
nmon a shared library and getting no output, forgetting that release/shared libraries are often built without a regular symbol table — usenm -Dfor the dynamic symbol table instead. - Trying to match C++ symbol names by eye without
-C, and being confused by mangled names like_ZN3Foo3barEi— always demangle with-Cwhen working with C++ binaries. - Assuming a symbol marked undefined (
U) is a bug — it's often expected and simply means the definition lives in another translation unit or library that will be linked in later. - Forgetting that
nmon a fully stripped binary (seestrip) will show little or no symbol information, since stripping removes exactly the datanmreads.
Tips
- When chasing an "undefined reference" linker error, run
nm -uon the failing object file to get the exact symbol name the linker is looking for, then grep for that name across candidate libraries. - Use
-Cby default when working with C++ code — mangled names are nearly unreadable without it. nm -Dis essential for shared libraries (.sofiles), which typically only carry a dynamic symbol table, not a full one.- Combine
nmwithgrepand shell loops to search across many object files or libraries at once when hunting a specific symbol.
Best practices
- Use
nm -uas a first diagnostic step for any "undefined reference" linker error before guessing at missing-lflags or include paths. - Always demangle C++ output with
-Cto avoid misreading mangled names as unrelated symbols. - Check
nm -D --defined-onlyon a shared library to confirm its public API before relying on it, especially for libraries without clear documentation. - Keep an unstripped build artifact around during development so
nm(and other debugging tools) can still provide useful symbol information; strip only final release builds.
Try it yourself
A simulated shell with a sample home directory — experiment freely, nothing leaves your browser. Type help to list supported commands.
Real-world use cases
- Diagnosing a linker error by confirming exactly which object file references an undefined symbol and searching libraries for its definition.
- Verifying a shared library actually exports the functions an application expects to dynamically link against.
- Auditing a compiled binary to confirm no unexpected internal functions were accidentally exported as global symbols.
- Investigating ABI compatibility issues between library versions by comparing their exported symbol lists.
Common interview questions
- What does an undefined symbol (U) in nm output mean? It means the object file references that symbol but doesn't define it itself — the linker must find its definition in another object file or library to successfully link.
- Why would nm show no output on a shared library? Many shared libraries are built without a regular symbol table; use nm -D to read the dynamic symbol table instead, which is what's actually used for runtime linking.
- Why are C++ symbol names in nm output often unreadable? Because C++ compilers mangle names to encode namespace, class, and argument type information for overload resolution; nm -C demangles them back into human-readable form.
- How would you debug an 'undefined reference to X' linker error using nm? Run nm -u on the object file that fails to link to confirm the exact expected symbol name, then run nm (or nm -D for shared libs) on candidate libraries to find which one, if any, actually defines it.
Frequently Asked Questions
What does an undefined symbol in nm output mean?
A symbol shown as undefined (typically marked U) is referenced in that object file but not defined there — the linker expects to find its definition in another object file or library. Running nm -u is a quick way to see exactly what a .o file expects to be supplied at link time.
How do I use nm to debug an 'undefined reference' linker error?
Run nm -u on the object file that's failing to link to confirm the exact symbol name it expects, then run nm on candidate libraries (with -D for shared libraries) to check whether any of them actually define that symbol, and under what exact name — mismatches are often due to name mangling or missing extern "C".
Why do C++ symbol names look garbled in nm output?
C++ compilers mangle function and method names to encode their namespace, class, argument types, and overload information into a unique linker symbol. Use nm -C to demangle these back into readable names like MyClass::doWork(int).
What's the difference between plain nm and nm -D?
Plain nm reads the regular symbol table, which is often stripped from shared libraries and release executables. nm -D reads the dynamic symbol table instead, which is what's actually used for runtime dynamic linking and remains present even when the regular symbol table is stripped.
Cheat sheet
Download a quick-reference cheat sheet for nm.