Using nm to troubleshoot linking problems

When one starts using libraries, an problem that happens often is a linking error. Compilation went through but the linker complains that it cannot find something. A useful tool in this respect is nm and I will describe below how one can employ it. I will do it with my gcc example

Compiling and Linking: Simple Example with gcc
http://matrixprogramming.com/2008/03/compilelink

but please not that nm on Windows (for example under Cygwin) is able to work with object files and libraries from MS VS. Hence the text could be used in this case as well (just change .o to .obj and .a to .lib).

I assume that you have already done points 1) to 3) and now we are at the point 4) Linking application with the library. Instead of issuing a correct command to link with the library, let us try to make a binary  just from main.o.

$ g++ -o main main.o
main.o:main.cpp:(.text+0x1e): undefined reference to `testlib(int)'
collect2: ld returned 1 exit status

Now we have a typical linking error and I hope that it is understandable. In main.cpp there is a call of testlib but there is no definition of such a function. We know where this function resides but let us imagine for a moment that we are not sure in that.

nm shows what symbols are defined in the object file

$ nm main.o
00000000 b .bss
00000000 d .data
00000000 d .eh_frame
00000000 t .text
U __Z7testlibi
U ___gxx_personality_v0
U ___main
00000000 T _main

Please note that we do not see testlib but rather __Z7testlibi. This happens because of name mangling in C++ (this does not happen in C or Fortran where the difference could be just in underscore). We can force nm to show names before name mangling

$ nm -C main.o
00000000 b .bss
00000000 d .data
00000000 d .eh_frame
00000000 t .text
U testlib(int)
U __gxx_personality_v0
U __main
00000000 T main

Then we see the name as written in the code. What is more important here is however the symbol U before the function name. It says that this function is not defined in the object file and the linker should take it either from other object file or from the library.

Usually the list of name is long and one can use grep to find the lines that are of interest, for example

$ nm main.o | grep testlib
U __Z7testlibi

This confirms the message from the linker.  "undefined reference to `testlib(int)" means exactly this, that in the object file there is a symbol with U as shown by nm. Now we suspect that this symbol is defined in libtestlib.a and want to check it with nm.

$ nm ../lib/libtestlib.a | grep testlib
testlib.o:
0000003e t __GLOBAL__D__Z7testlibi
0000005a t __GLOBAL__I__Z7testlibi
00000076 T __Z7testlibi

nm confirms that the function is there, as we see T before the function name.

This is basically what should be done when you see the linking error. The goal is to undertand what library has symbols required by the linker and nm can help you to find the answer.

If you have many libraries to check for a given symbol, you may find useful my script findlib:

#!/bin/bash
#to find a library that contains a given symbol
#Use:
#findlib sym libs
sym="$1"
shift
for name do
  echo $name
  nm $name | grep sym
done

More information:

$ man nm
$ info nm


Comments

2 responses to “Using nm to troubleshoot linking problems”

Comments are now closed
  1. Bernard says:

    Thanks for the “findlib” script, but it has a small typo:

    nm $name | grep sym

    should be …

    nm $name | grep $sym

    Bernard

  2. I am not sure if I agree because I have

    sym=”$1″

    at the beginning.