nm(1)

Development tool

Lists the symbols of a .o or a library: defined functions (T), symbols expected from elsewhere (U), variables (D, B). The tool for undefined reference errors.

Synopsis
nm [options] file...

Description

nm reads an object file (.o), a library (.a, .so) or an executable, and prints its symbol table: the global functions and variables it defines, and the ones it uses without defining them. Each line gives the symbol's address within its section, a letter for its type, then its name. This is the linker's view of your program, and the fastest way to understand an undefined reference or multiple definition error.

Reading the letter

LetterMeaning
Tfunction defined in this file (code section)
Usymbol used here but defined elsewhere, to be provided by another file or a library
Dglobal variable initialized with a nonzero value
Bglobal variable left uninitialized, or initialized to zero
Rread-only data, such as a const array
Wweak symbol, which another definition can replace

An uppercase letter marks a global symbol, visible to other files. A lowercase letter marks a local symbol: a static function or variable, which the linker will never offer to another file.

Useful options

OptionEffect
-ushows only the undefined symbols (U)
-gshows only the global symbols
-Dreads the dynamic symbols of a shared library (.so)
-Aprefixes each line with the file name, handy with grep

Example

score.c
#include <stdio.h>
int best = 20;int last;const char title[] = "Scores";
static int twice(int n){    return 2 * n;}
void show(int n){    printf("%s: %d\n", title, twice(n));}
Terminal
$ gcc -c score.c$ nm score.o0000000000000000 D best0000000000000000 B last                 U printf0000000000000018 T show0000000000000000 R title0000000000000000 t twice$ nm -u score.o                 U printf

Every declaration is there: best initialized (D), last without a value (B), title read-only (R), show global (T), twice in lowercase because it is static. printf is expected (U): the C library will provide it at link time.

To find out which shared library defines a function, -D and grep are enough. On Debian, sqrt lives in libm, not in libc, hence the -lm:

Terminal
$ nm -D /lib/aarch64-linux-gnu/libm.so.6 | grep -w sqrt0000000000013840 W sqrt@@GLIBC_2.17$ nm -D /lib/aarch64-linux-gnu/libc.so.6 | grep -w sqrt

Pitfalls

  • The addresses in a .o are relative to each section and are often 0: they only become final after linking.

  • A static function shows up in lowercase (t). If another file calls it, linking fails even though nm lists it.

  • A shared library passed to nm without -D can answer no symbols when its regular symbol table has been stripped: use -D.

  • Library paths depend on the distribution and the architecture. The example comes from a 64-bit ARM machine.

  • The full method for fixing an undefined reference is in undefined reference to in C.

Now write it yourself.