gcclinkershared-librariesopenocd

What happens when an executable can't find a symbol in dynamic library?


I would like to use openOCD as my debugger to interact with the J-Link adapter on my board. So I download the code from a mirror repository openocd - github and follow the step in README to build it.

  ./bootstrap (when building from the git repository)
  ./configure [options]
  make
  sudo make install

And the configure threw a error:

configure: error: libjaylink-0.2 is required for the SEGGER J-Link Programmer

So I built libjaylink from libjaylink - gitlab and finally got libjaylink.a and libjaylink.so in /usr/local/lib.

After that the build process is smooth and link all the object files into an executable ./src/openocd:

libtool: link: ( cd "src/.libs" && rm -f "libopenocd.la" && ln -s "../libopenocd.la" "libopenocd.la" )
/bin/bash ./libtool  --tag=CC   --mode=link gcc -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Wpointer-arith -Wundef -Werror -g -O2   -o src/openocd src/main.o src/libopenocd.la  ./jimtcl/libjim.a  -lutil -ldl 
libtool: link: gcc -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Wpointer-arith -Wundef -Werror -g -O2 -o src/openocd src/main.o  src/.libs/libopenocd.a -L/usr/lib/x86_64-linux-gnu -L/usr/local/lib /usr/local/lib/libjaylink.so -lusb-1.0 -lm ./jimtcl/libjim.a -lutil -ldl

In my limited experience with linking, the global function symbol in libjaylink.so should be callable in ./src/openocd.

But openocd threw an error when running:

$ ./src/openocd -f interface/jlink.cfg target/stm32f4x.cfg

./src/openocd: symbol lookup error: ./src/openocd: undefined symbol: jaylink_device_get_usb_bus_ports

But it should be in libjaylink.so

$ objdump -t /usr/local/lib/libjaylink.so

...
0000000000004150 g     F .text  00000000000000c9              jaylink_device_get_usb_bus_ports
0000000000004110 g     F .text  0000000000000036              jaylink_device_get_usb_address
...

Wanted to know if there's something I overlook in dynamic linking or there's some step I can follow to find out problem. orz


Solution

  • What happens when an executable can't find a symbol in dynamic library?

    When the executable calls a function (jaylink_device_get_usb_bus_ports() here), the runtime loader (ld-linux here) searches all the shared libraries loaded into the current process, and if the symbol can't be found in any of them, the process is terminated (by calling _exit).

    objdump ...

    You should not call objdump on ELF binaries for reasons explained here. Use readelf -s instead. Here the better choice would be to use nm -D instead.

    some step I can follow to find out problem.

    The first order of business is to verify that libjaylink.so in fact defines the jaylink_device_get_usb_bus_ports() as an exported function:

    nm -D /usr/local/lib/libjaylink.so | grep jaylink_device_get_usb_bus_ports
    

    If the output looks anything other than ...hex-address... T jaylink_device_get_usb_bus_ports, then it doesn't (and that would need to be debugged separately).

    If the output does look correct, you next need to find out whether your ./src/openocd binary is actually using the version of the library you think it is using. Run ldd ./src/openocd, chances are there is some other version of libjaylink.so somewhere on your system.

    If the correct library is used, and that library does define the symbol, then further debugging can be accomplished by running

    LD_DEBUG=libs,symbols ./src/openocd -f interface/jlink.cfg target/stm32f4x.cfg
    

    This will produce a lot of output and will likely provide a clue as to what went wrong.