GNU nm

1. Overview

nm is a GNU Binutils tool used to display the symbols contained in object files, executables, shared libraries, and static libraries.

Its primary purpose is to inspect symbol tables during compilation and linking. It helps reveal how names from source code appear in compiled binaries and how those names are resolved across translation units and libraries.

Typical symbols shown by nm include:

  • functions
  • global variables
  • undefined external references
  • weak symbols
  • debugging symbols
  • section-related special symbols

In essence, nm is a symbol inspection tool.

2. Original design goals

The original design goal of nm is to provide a simple way to examine symbol information in binary files.

It is especially useful for understanding:

  • which symbols are defined in a file
  • which symbols are referenced but not yet resolved
  • whether a symbol is local or global
  • what kind of symbol it is
  • where the linker may obtain or fail to obtain a symbol

So nm is not mainly for disassembly or source-level debugging. Its role is narrower and more focused: it exposes the symbol-level structure of compiled files.

2.1. Basic usage

The basic form is:

nm file

If no file is specified, GNU nm uses a.out by default.

Examples:

nm main.o
nm libfoo.a
nm a.out
nm libfoo.so

Default output usually contains three pieces of information for each symbol:

  1. symbol value or address
  2. symbol type
  3. symbol name

Example:

0000000000001139 T main
                 U printf
0000000000004010 D global_var
0000000000004020 B uninitialized_var

Interpretation:

  • main is defined in the text section
  • printf is undefined here and must be resolved elsewhere
  • global_var is initialized data
  • uninitialized_var is in the BSS area

2.2. Core symbol type letters

The most important symbol letters are:

T / t
text section, usually code
D / d
initialized data
B / b
uninitialized or zero-initialized data
R / r
read-only data
U
undefined symbol
W / w
weak symbol
V / v
weak object
A
absolute symbol
C / c
common symbol
N
debugging symbol
I
indirect reference
?
unknown or format-specific

In general:

  • uppercase letters usually indicate global or external symbols
  • lowercase letters usually indicate local symbols

The most important letters to remember for everyday usage are:

  • T
  • D
  • B
  • R
  • U
  • W

2.3. Most commonly used options

2.3.1. -C / --demangle

Demangles C++ symbol names into readable function and class names.

nm -C libfoo.a

Very common in C++ projects.

2.3.2. -g / --extern-only

Shows only external or global symbols.

nm -g main.o

Useful when local symbols are irrelevant and only exported/imported symbols matter.

2.3.3. -u / --undefined-only

Shows only undefined symbols.

nm -u main.o

This is especially useful when diagnosing linker errors.

2.3.4. -U / --defined-only

Shows only defined symbols.

nm -U libfoo.a

Useful when checking what a file or library actually provides.

2.3.5. -D / --dynamic

Shows dynamic symbols rather than the normal symbol table.

nm -D libfoo.so

Important for shared libraries and dynamically linked executables.

2.3.6. -n / --numeric-sort

Sorts symbols by numeric address rather than by name.

nm -n a.out

Useful for understanding layout in address order.

2.3.7. -A / -o / --print-file-name

Prints the file name before each symbol.

nm -A *.o

Useful when inspecting many files at once.

2.3.8. -l / --line-numbers

Tries to display source file and line number information.

nm -l a.out

Works best when debug information is present.

2.3.9. -S / --print-size

Prints symbol size in addition to value.

nm -S a.out

Useful for code size or object size inspection.

2.3.10. --size-sort

Sorts symbols by size.

nm --size-sort -S a.out

Useful for finding large functions or objects.

2.3.11. -a / --debug-syms

Includes debugger-only symbols.

nm -a a.out

Less common in everyday work, but useful for full inspection.

2.4. Common usage scenarios

2.4.1. Diagnosing linker errors

A common linker error is:

undefined reference to `foo`

To inspect unresolved references in an object file:

nm -u main.o

To search for the file or library that defines foo:

nm libfoo.a | grep ' foo$'

This is one of the classic uses of nm.

2.4.2. Inspecting what a library exports

For a static library:

nm -g libmylib.a

For a shared library:

nm -D -g libmylib.so

This helps identify the API visible to other code.

2.4.3. Understanding object file contents

To inspect what a single object file contains:

nm file.o

This reveals:

  • which functions are defined
  • which global variables are defined
  • which symbols are still unresolved
  • what section each symbol belongs to

This makes nm very useful for learning compilation and linking.

2.4.4. Inspecting C++ binaries

C++ binaries often contain mangled names. The following form makes them readable:

nm -C a.out

This is useful for examining namespaces, overloaded functions, class methods, and template instantiations.

2.4.5. Checking weak vs strong symbols

When symbol resolution behaves unexpectedly, nm can reveal whether a symbol is weak or strong.

Weak symbols often appear as:

  • W
  • w
  • V
  • v

This is useful in runtime libraries, low-level systems code, and large C/C++ projects.

2.4.6. Inspecting static archive indexes

For static libraries, the archive symbol index can be displayed with:

nm -s libfoo.a

This is helpful when studying how symbol lookup works inside .a archives.

2.5. Advanced usages

2.5.1. Dynamic symbol table inspection

For shared libraries or dynamically linked executables:

nm -D libfoo.so

This focuses on the dynamic symbol table, which is especially relevant for runtime linking.

2.5.2. Size analysis

To inspect symbols together with size information:

nm -S --size-sort a.out

This is useful for:

  • code size optimization
  • embedded systems work
  • tracking binary growth
  • locating unusually large functions or objects

2.5.3. Source line mapping

When debug information is available:

nm -l a.out
nm -l --inlines a.out

This can associate symbols with source file and line information.

2.5.4. Working with plugin-based or LTO objects

GNU nm supports plugins and can be used with LTO-related objects.

Example:

nm --plugin /path/to/plugin file.o

This is relevant in more advanced toolchain setups where ordinary nm output may not fully expose LTO-generated symbol information.

2.5.5. Choosing output formats

GNU nm supports different output styles, including:

  • bsd
  • sysv
  • posix
  • just-symbols

Examples:

nm -f sysv a.out
nm -P a.out
nm -j a.out

These are useful for:

  • scripting
  • portability
  • machine-friendly output
  • compatibility with other tools

2.5.6. Inspecting many files at once

When analyzing many object files or archive members:

nm -A *.o
nm -A libfoo.a

This makes it easier to determine which file contributes which symbol.

2.5.7. Showing synthetic or special symbols

GNU nm can also show linker-generated or target-specific symbols:

nm --synthetic a.out
nm --special-syms a.out

This is mainly useful in advanced ABI, linker, or target-format investigation.

2.6. Mental model

nm can be understood as answering four main questions:

  1. What symbols does this file define?

    nm -U file.o
    
  2. What symbols does this file still need?

    nm -u file.o
    
  3. What kinds of symbols are they? This is determined by the symbol type letters such as T, D, B, R, U, and W.
  4. Are these ordinary symbols or dynamic-linking symbols?

    nm file
    nm -D file
    

This is the core conceptual model of nm.

2.7. Compact cheat sheet

nm file.o                 # basic symbol table
nm -C file.o              # demangle C++ names
nm -u file.o              # undefined symbols only
nm -U file.o              # defined symbols only
nm -g file.o              # external/global symbols only
nm -D libfoo.so           # dynamic symbols
nm -n a.out               # sort by address
nm -S --size-sort a.out   # show sizes and sort by size
nm -A *.o                 # print file name with each symbol
nm -l a.out               # show line number information
nm -s libfoo.a            # show archive index

2.8. Final summary

nm is a focused binary analysis tool for inspecting symbol tables.

Its main strengths are:

  • diagnosing linker problems
  • checking undefined references
  • seeing what a library exports
  • understanding symbol layout in compiled files
  • reading mangled C++ names in human-readable form

Compared with tools like objdump or readelf, nm is simpler and narrower in scope. Its core task is to expose symbol information clearly and directly.

Author: Lowtroo

Created on: 2026-04-10 Fri 13:36

Powered by Emacs 29.3 (Org mode 9.6.15)