Inspect AArch64 symbols with gcc-nm-13 and its GCC plugin
You will use aarch64-linux-gnu-gcc-nm-13 to list symbols from an AArch64 object, executable or shared library, while letting the GCC 13 wrapper select its linker plugin. Allow about ten minutes if the file is ready. The commands below only read the input and print a report, so they normally need no elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the installed wrapper
The two local manual pages describe the same command: gcc-nm is a wrapper around nm that adds the appropriate --plugin option for GCC 13. The command name with the -13 suffix is the canonical installed form; aarch64-linux-gnu-gcc-nm is its unversioned alias.
$ command -v aarch64-linux-gnu-gcc-nm-13
/usr/bin/aarch64-linux-gnu-gcc-nm-13
$ aarch64-linux-gnu-gcc-nm-13 --version
GNU nm (GNU Binutils for Ubuntu) 2.42
On this machine the packages are gcc-13-aarch64-linux-gnu 13.3.0-6ubuntu2~24.04.1cross1 and binutils-aarch64-linux-gnu 2.42-4ubuntu2.10. The wrapper identifies the nm implementation, so its version output is not a separate GCC compiler version.
Checkpoint
The command resolves to the cross-toolchain wrapper and reports GNU nm. If it is missing, install the distribution's AArch64 GCC and Binutils packages through your normal package-management process. Do not use sudo merely to inspect a file you can already read.
2. List symbols from one input
Pass an input file after the options. With no input, GNU nm assumes a.out, which is an easy distraction when you meant to inspect a named build artefact.
$ aarch64-linux-gnu-gcc-nm-13 /path/to/program-or-library
The default BSD-style report contains a value, a one-character type and a symbol name. Uppercase types usually describe global symbols, while lowercase types usually describe local symbols. A T or t entry is code in a text section, D or d is initialised data, and U is an undefined reference. Exact types depend on the object format.
For a compact, script-friendly report, use the POSIX format:
$ aarch64-linux-gnu-gcc-nm-13 -P /path/to/program-or-library | sed -n '1,12p'
symbol_name T 0000000000000000 0000000000000030
The displayed address and size will differ for your file. The sed limit keeps an exploratory command from filling your terminal; remove it when you need the complete list.
3. Narrow the report before reading it
Start with one filter, then add another only when the result is still too large. These are nm options passed through by the wrapper:
-gor--extern-onlyshows external symbols.-uor--undefined-onlyshows unresolved references.-Uor--defined-onlyshows defined symbols.-Dor--dynamicselects the dynamic symbol table in a shared object or other dynamic file.-Cor--demanglemakes C++ names easier to read.-Aor--print-file-nameprefixes symbols with their input file, which is useful for several files or archive members.
For example, this checks exported dynamic symbols without dumping ordinary static symbols:
$ aarch64-linux-gnu-gcc-nm-13 -D -g -P /path/to/libexample.so | sed -n '1,20p'
exported_name T 0000000000000000 0000000000000040
Checkpoint
Use -u when looking for dependencies, -D when investigating a shared library's runtime interface, and neither when you need the full normal symbol table. An empty result can be a correct filter result, not proof that the file is corrupt.
4. Understand what the wrapper changes
The wrapper's useful difference is not a new symbol format. It invokes the target nm with a GCC linker plugin path. On this installation, tracing the help command shows the extra argument as --plugin /usr/libexec/gcc-cross/aarch64-linux-gnu/13/liblto_plugin.so. This helps nm understand link-time-optimised inputs when the plugin supports them.
$ strace -f -e execve -o /tmp/gcc-nm-trace.log \
aarch64-linux-gnu-gcc-nm-13 -h
$ grep -- '--plugin' /tmp/gcc-nm-trace.log
execve(".../aarch64-linux-gnu/bin/nm", [..., "--plugin", ".../13/liblto_plugin.so", ...], ...)
The trace is optional and requires strace. The abbreviated paths in the example are intentional because the exact multiarch path is installation-specific. Do not confuse nm's --plugin with the linker's -plugin option, and do not copy a plugin into a system directory just to make this wrapper work. The wrapper already supplies the configured GCC plugin.
5. Handle failures without changing the build
First identify the input and its format:
$ file /path/to/program-or-library
$ test -r /path/to/program-or-library && echo readable
$ aarch64-linux-gnu-gcc-nm-13 -V
If nm says the file has no symbols, it may be a stripped executable, a file containing only dynamic symbols, or simply the wrong input. Try -D for a dynamic object, or inspect the unstripped build artefact. If it reports an unrecognised format, confirm that the file is an AArch64 ELF file rather than a source file, archive from another target, or text file.
If you explicitly pass --plugin, it replaces the wrapper's normal plugin argument. A missing or incompatible plugin can therefore make a previously working command fail. Remove the manual override and retry with the wrapper's default:
$ aarch64-linux-gnu-gcc-nm-13 /path/to/program-or-library
Do not run nm as root to bypass a permissions error. Fix the file permissions or ask the owner for a readable copy. Nothing in this guide changes the input, the linker plugin, or the system's symbol tables, so there is no undo operation beyond removing any optional trace file from /tmp.
Done means
- The GCC 13 AArch64 wrapper resolves and reports the installed GNU nm version.
- You passed the intended ELF object, executable or library explicitly.
- You chose normal, dynamic, defined, undefined or external symbols deliberately.
- For C++ output, you used demangling only when readable names were needed.
- You left the input, plugin installation and build tree unchanged.