dynamic library loading with linking to static library - c++

I have a program structure that has
static library(ACE)
static library(common.a)
dynamic library plugin 1(1.so)
plugin 2(2.so) and executable
plugin1, plugin2 and executable all use both common.a and libACE.a
Follow the tutorial here: http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html.
I only link those two static library when compiling the executable as shown below:
g++ -g -DUNIX -DLINUX -Wall -D__NUMBER_FIELD_ID__ -I/opt/ACE_wrappers -Ilib/ -I. -I./common -I./common/lib -I../inc -I/opt/pct/pctlib/inc -o acs_d acs_d.o -L../lib -Wl,--export-dynamic -rdynamic -Wl,--whole-archive /opt/ACE_wrappers/ace/libACE.a common/libcommon_d.a -Wl,--no-whole-archive -ldl -lrt -lpthread
The point is, when I use dlopen to open those two plugins, one succeeds and one fails
The successful one use more ACE functions and the error is complaining undefined symbol as shown below:
[CModuleMgr] loadCModule(): Errors occurred when opening the module. nCModuleId[1] pLibHandle[(nil)] sCModulePath[/opt/acs/adapter/libadapter_d.so] sError[/opt/acs/adapter/libadapter_d.so: undefined symbol: _ZN17ACE_Event_Handler10set_handleEi]
For the main program, I have tried to use command nm to find the symbol
$ nm acs_d | grep _ZN17ACE_Event_Handler10set_handleEi
000000000048f240 t _ZN17ACE_Event_Handler10set_handleEi
It is there, but the plugin cannot find it! I have used option like -Wl,--export-dynamic -rdynamic -Wl,--whole-archive. But it still cannot find this symbol. any idea?

It is there, but the plugin cannot find it!
No, the symbol is not there!
Or rather, the symbol has internal linkage (t), and is not visible or usable outside of the ELF image into which it is linked. Globally visible symbols have external (T) linkage.
The most likely cause for the symbol to have t linkage is that the symbol has __attribute__((visibility("hidden"))) at the source level. Documentation here.
Why ACE developers marked it as such, I don't know.

Related

Linker error undefined reference even if functions are defined in shared library

I´m trying to modify a piece of C++ code (developed under Linux with gcc toolchain) using in it new functions that are defined in two libraries, one shared library (called libsio4_api.so) and a static library (called sio4_main.a). The original code is built with a makefile that first creates a shared library linking toghether various object files and then links this library with the main object file.
This is the line that links the shared library:
g++ -s -shared main.o RTLinkResolution.o IORefresh.o UserProgramImpl.o UserProgramDataManager.o UserProgramCode.o -L./genericFiles/lib -lUserProgramEnvironment -lm -o libUProg.so
I modified it in this way to add to the linkage my libraries (-pthread is needed by one of them):
g++ -s -shared -pthread libsio4_api.so sio4_main.a main.o RTLinkResolution.o IORefresh.o UserProgramImpl.o UserProgramDataManager.o UserProgramCode.o -L./genericFiles/lib -lUserProgramEnvironment -lm -o libUProg.so
This linking terminate without errors and in the resulting lib I can see the functions I want to use (in this example I show just one but also the others are present):
nm -D libUProg.so | grep sio4_async_init
000000000006d581 T sio4_async_init
000000000006dcae T sio4_async_init_data
U _Z15sio4_async_initv
The problem is that when the final linking is done the functions are not found:
g++ -o test main.o libUProg.so -pthread sio4_main.a libsio4_api.so
libUProg.so: undefined reference to `sio4_async_close(int)'
libUProg.so: undefined reference to `sio4_async_init()'
libUProg.so: undefined reference to `sio4_async_open(int, int, int*)'
I searched already for similar problems in other topics and I found out that the order in which libraries are fed to the linker is important, but even if I change the order in the final linking command those functions are not found.
Does someone have any clue about how I can proceed?

Undefined references even though library is linking and it contains correct symbols

I am trying to compile my executable with this line from my Makefile:
g++-8.1.0 -Wall -Wextra -pthread -std=c++17 -ggdb3 -I/usr/local/include ./src/barometer.o ./src/serial.o ./src/ptpcontroller.o ./src/stream.o ./src/helper.o ./src/thetav.o ./src/gps.o ./src/flightcontroller.o ./src/gui.o ./src/maneuvers.o ./src/main.o ./src/fcinterface.o ./libs/NemaTode/src/NumberConversion.o ./libs/NemaTode/src/NMEAParser.o ./libs/NemaTode/src/GPSFix.o ./libs/NemaTode/src/NMEACommand.o ./libs/NemaTode/src/GPSService.o ./libs/ptpcam/ptpcam.o -o halo -L/usr/local/lib -lwiringPi -lrt -lpigpio -lncurses -lptp2 -lusb
And I get lots of undefined reference errors like this:
./libs/ptpcam/ptpcam.o: In function `init_ptp_usb(_PTPParams*, _PTP_USB*, usb_device*)':
/home/pi/ProjectHaloDrone/RPiCM3/libs/ptpcam/ptpcam.cpp:322: undefined reference to `ptp_usb_sendreq(_PTPParams*, _PTPContainer*)'
Even though all these symbols are in the libptp2 library that I am linking against with -lptp2:
pi#raspberrypi:~/ProjectHaloDrone/RPiCM3 $ nm -g /usr/local/lib/libptp2.so | grep ptp_usb_sendreq
00002d3c T ptp_usb_sendreq
I am very confused why the linker thinks the symbols aren't defined...
The fact that linker reports unresolved external symbols as ptp_usb_sendreq(_PTPParams*, _PTPContainer*) means that those symbols are mangled in C++ way (otherwise, function arguments would not be visible).
At the same time, nm reports the symbol as ptp_usb_sendreq, which means, it is not mangled.
Most likely solution: check and make sure your function signature (likely in a header file) is wrapped in extern "C" specifier.

Linking In Dependencies of a Shared Library

I created a library that I'd like others to use.
To Compile My library:
/usr/bin/g++ -fPIC -shared -Wl,-soname,libMYLIB.so [inputs] -lboost_system -lboost_thread
To Compile a Binary:
/usr/bin/g++ myTest.cpp -lMYLIB -lboost_system
I would like that line to only be:
/usr/bin/g++ myTest.cpp -lMYLIB
How do I avoid having to specify my libraries dependencies later? What flag in the linker or compiler am I looking for?
There is a linker option (I mean ld linker http://linux.die.net/man/1/ld) --unresolved-symbols=ignore-all or -unresolved-symbols=ignore-in-object-files:
Determine how to handle unresolved symbols. There are four possible values for method:
* ignore-all
Do not report any unresolved symbols.
* report-all
Report all unresolved symbols. This is the default.
* ignore-in-object-files
Report unresolved symbols that are contained in shared libraries, but ignore them if they come from regular object files.
* ignore-in-shared-libs
Report unresolved symbols that come from regular object files, but ignore them if they come from shared libraries. This can be useful
when creating a dynamic binary and it is known that all the shared
libraries that it should be referencing are included on the linker's
command line.
And this is an example. I have a library libmylib.so and an application main:
So first I build the library:
$ g++ -fpic -shared mylib.cpp -o libmylib.so
When I build the application but I do not add -lmylib on command line. Normally it results in error Unresolved external symbols but since I add -Wl,--unresolved-symbols=ignore-in-object-files to the command line I get no errors:
$ g++ -fpic -g main.cpp -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-rpath,.
Then I run my program:
$ ./a.out
./a.out: symbol lookup error: ./a.out: undefined symbol: _Z7my_funcd
It doesn't work as expected but then I use LD_PRELOAD:
$ LD_PRELOAD=./libmylib.so ./a.out
2
So with LD_PRELOAD it works

Undefined symbol when trying to load a library with dlopen

I'm trying to load a shared library (plugin) I was provided (closed source) with dlopen under a Linux ARM platform. I'm trying to load this way:
void* handle = dlopen(<library_path>/<library_name>, RTLD_NOW);
The result is a failure with this message:
Failed to load <library_path>/<library_name>: undefined symbol: <symbol_name>.
I tried to look inside the library with nm, but it seems the lib was stripped, no symbol could be found. I also tried using readelf -s, and, in fact, I got this result:
12663: 00000000 0 NOTYPE GLOBAL DEFAULT UND <symbol_name>
By reading around, I get that readelf -s returns all the symbols, including those symbols defined in libraries referenced by it.
The answers to this question are not completely clear to me: is this a symbol which is supposed to be in the library and which is not there because it was compiled the wrong way or is this a symbol I'm supposed find somewhere else? The output of readelf -d seems to suggest I'm providing all the needed shared libraries. May this error be related to a mistake in the way I'm compiling my executable or is this something not related to the loader?
Also, I read about the meaning of each column, but those values are quite strange. How do you interpret that symbol description? Why is address 0? Why is type NOTYPE?
undefined symbol: X means always that X should be exported from one of loaded libraries, but it's not. You should find out in which library requested symbol is and link to it.
You should know that this message is always result of problem with library, it's not fault. Library should know how to get all it's symbols. If it doesn't you can link your executable to required library so when you load your plugin, requested symbol is already known.
This error might have more complex reason. In case when both plugin and main app are linking to library, then attempts to link it might end with undefined symbols anyway. This might happen if main app and plugin are using different version of library (namely plugin uses newer one). Then at the point of loading plugin older version is already loaded, so loader assumes everything is ok, but newer version might contain new symbols. If plugin uses them, you will get undefined symbol errors.
This problem appears also if the order of the static libraries in the linking command is wrong for the app. The Unix ld linker requires that the library which implements a function is specified after the library which refers the function.
I got this trouble when I was trying to build libtesseract shared library taking libz library from a custom location (not a standard libz from the host, but manually built from source as well). I have put an example below:
Wrong linking order (-lz before -llept):
$ g++ -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o -Wl,--whole-archive ....(some libs) -Wl,--no-whole-archive -L/home/build/jenkins/workspace/tesseract/zlib/bin/lib -L/home/build/jenkins/workspace/tesseract/leptonica/bin/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/x86_64-linux-gnu -lz -llept -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o -g -O2 -Wl,-soname -Wl,libtesseract.so.4 -o .libs/libtesseract.so.4.0.1
Check with "nm -D":
$ nm -D .libs/libtesseract.so.4.0.1 | grep deflateInit
U deflateInit_
Check with "dlopen":
Cannot load ./tesseract/src/api/.libs/libtesseract.so.4.0.1 (./tesseract/src/api/.libs/libtesseract.so.4.0.1: undefined symbol: deflateInit_)
It happens because the linker is processing in the loop all static libraries passed in the command line and skipping those which are not used by any of the preceeding ones. Since on the moment of checking of libz.a the linker sees that all of already checked libraries do not use any function from libz.a the linker just "forgets" libz.a.
Proper linking order (-lz after -llept):
$ g++ -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o -Wl,--whole-archive ....(some libs) -Wl,--no-whole-archive -L/home/build/jenkins/workspace/tesseract/zlib/bin/lib -L/home/build/jenkins/workspace/tesseract/leptonica/bin/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/x86_64-linux-gnu -llept -lz -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o -g -O2 -Wl,-soname -Wl,libtesseract.so.4 -o .libs/libtesseract.so.4.0.1
Check with "nm -D":
$ nm -D .libs/libtesseract.so.4.0.1 | grep deflateInit
000000000041fb5b T deflateInit_
000000000041fba3 T deflateInit2_
"dlopen" did not show this error this time.

GCC and ld can't find exported symbols...but they're there

I have a C++ library and a C++ application trying to use functions and classes exported from the library. The library builds fine and the application compiles but fails to link. The errors I get follow this form:
app-source-file.cpp:(.text+0x2fdb): undefined reference to `lib-namespace::GetStatusStr(int)'
Classes in the library seem to be resolved just fine by the linker, but free functions and exported data (like a cosine lookup table) invariably result in the above error.
I am using Ubuntu 8.04 (Hardy), and it is up to date with the latest Ubuntu packages.
The command to link the library is (with other libraries removed):
g++ -fPIC -Wall -O3 -shared -Wl,-soname,lib-in-question.so -o ~/project/lib/release/lib-in-question.so
The command to link the application is (with other libraries removed):
g++ -fPIC -Wall -O3 -L~/project/lib/release -llib-in-question -o ~/project/release/app-in-question
Finally, it appears (as best as I can tell) that the symbols in question are being exported properly:
nm -D ~/project/lib/release/lib-in-question.so | grep GetStatusStr --> U _ZN3lib-namespace12GetStatusStrEi
the U before _ZN3lib-namespace12GetStatusStrEi in the nm output shows that the symbol is undefined in the library.
Maybe it's defined in the wrong namespace: it looks like you're calling it in lib-namepace but you might be defining it in another.
It's been a while, but if you specify a lib with the -l option, then don't you have the skip the lib prefix?
(I changed the name from "lib-in-question.so" to "libfoobar.so" for easier reading for the example below)
g++ -fPIC -Wall -O3 -L~/project/lib/release -lfoobar
or
g++ -fPIC -Wall -O3 ~/project/lib/release/libfoobar.so