Force unused function to export in shared library - c++

printme() and getme() defined in top.cpp and top.h
I used printme() function in test.cpp (test cpp file) in main function
g++34 -c top.cpp -fPIC
ar rcs libtop.a top.o
g++34 -c test.cpp -fPIC
g++34 -shared -o ltop.so -ltop -L. -fPIC
getme is not getting exported in ltop.so
How i can force getme function exported in ltop.so
When i do nm ltop.so
it is not showing getme symbol
i want to force this
Note: file can have multiple unused function like - getme()
I want to force all to export to so library

Normally, when linking with a static library only the modules in the static library that contain an unresolved symbol end up getting linked.
Here, since there is no unresolved reference to getme(), hence this module does not get linked from the static library. The solution is to explicitly make it unresolved.
A minor complicating factor is the C++ symbol name mangling. It is necessary to figure out what is the mangled symbol name for the getme() function. The easiest way is to look at the library with the nm command:
$ nm libtop.a
top.o:
0000000000000000 T _Z5getmei
Ok, so the mangled symbol name is _Z5getmei. The -u linker flag forces an unresolved reference to the indicated symbol to be used when linking:
g++ -shared -o ltop.so -L. -ltop -Wl,-u -Wl,_Z5getmei
The documentation for the -u option is found in the ld man page. This includes the module in the shared library:
$ nm ltop.so | grep getme
0000000000000680 T _Z5getmei

Don't use your static library to create your dynamic one. Instead, use the component object file directly:
g++34 -shared -o ltop.so -fPIC top.o
The reason is that when you specify a library with -l when compiling a binary, only unresolved external symbols from earlier in the compilation line are picked up. In your case, this is nothing, so precisely nothing is picked up in creating libtop.so from libtop.a
UPDATE: As an alternative, if the original object files are no longer available, youc an use the --whole-archive linker option to force it to include everything from a static library, rather than just unresolved externals:
g++34 -shared -o ltop.so -fPIC -Wl,--whole-archive ./libtop.a
Or:
g++34 -shared -o ltop.so -fPIC -Wl,--whole-archive -L. -ltop

Related

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.

How are external symbols resolved?

I have two files 37064544_p1.cpp & 37064544_p2.cpp with the same content as shown below :
int add(int x,int y)
{
return x+y;
}
I compiled them using
g++ -c 37064544_p2.cpp -o 37064544_p2.o
g++ -c 37064544_p2.cpp -o 37064544_p2.o
and added them to an archive using
ar -rsc lib37064544pf.a 37064544_p1.o 37064544_p2.o
And
$ nm -s lib37064544pf.a
gives me :
Archive index:
_Z3addii in 37064544_p1.o
_Z3addii in 37064544_p2.o
37064544_p1.o:
0000000000000000 T _Z3addii
37064544_p2.o:
0000000000000000 T _Z3addii
and
$ ar -t lib37064544pf.a
gives me
37064544_p1.o
37064544_p2.o
I have a driver which calls the _Z3addii function which is compiled with
g++ -static 37064544driver.cpp -o 37064544driver.elf -L. -l37064544pf
Result is
Sum : 11
Questions
How is the symbol _Z3addii resolved ?
Is it according to archive index?
Is it according to the order in which we populate the archive using ar?
How can I change this order?
How can I prevent ar from having duplicate symbols?
Compiler : g++ 4.6.3
How is the symbol _Z3addii resolved ?
The implementation is free to do whatever it likes, you are violating the one definition rule.
Realistically it'll stop looking for any given symbol after the first match, which presumably follows the order the files were inserted to the archive.
How can I change this order?
With ar you can use the a (after) and b (before) modifiers to position object files in the archive when inserting them, you're still violating the ODR though.
How can I prevent ar from having duplicate symbols?
You can't as far as I know, ar is relatively dumb and for good reason as some languages do allow for identical symbols, which is why you don't have any errors when linking with the archive (no diagnostic is required for ODR violations).
You can either force ld to read the entire archive
g++ -static 37064544driver.cpp -o 37064544driver.elf -L. \
-Wl,--whole-archive -l37064544pf -Wl,--no-whole-archive
Or you can do a partial link instead of a traditional archive which will give you an error if there are any duplicates
ld -r -o lib37064544pf.a 37064544_p1.o 37064544_p2.o

How to expose entrypoints from a library (.a) which is linked into a shared library (.so) [duplicate]

When compiling our project, we create several archives (static libraries), say liby.a and libz.a that each contains an object file defining a function y_function() and z_function(). Then, these archives are joined in a shared object, say libyz.so, that is one of our main distributable target.
g++ -fPIC -c -o y.o y.cpp
ar cr liby.a y.o
g++ -fPIC -c -o z.o z.cpp
ar cr libz.a z.o
g++ -shared -L. -ly -lz -o libyz.so
When using this shared object into the example program, say x.c, the link fails because of an undefined references to functions y_function() and z_function().
g++ x.o -L. -lyz -o xyz
It works however when I link the final executable directly with the archives (static libraries).
g++ x.o -L. -ly -lz -o xyz
My guess is that the object files contained in the archives are not linked into the shared library because they are not used in it. How to force inclusion?
Edit:
Inclusion can be forced using --whole-archive ld option. But if results in compilation errors:
g++ -shared '-Wl,--whole-archive' -L. -ly -lz -o libyz.so
/usr/lib/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x1d): undefined reference to `__init_array_end'
/usr/bin/ld: /usr/lib/libc_nonshared.a(elf-init.oS): relocation R_X86_64_PC32 against undefined hidden symbol `__init_array_end' can not be used when making a shared object
/usr/bin/ld: final link failed: Bad value
Any idea where this comes from?
You could try (ld(2)):
--whole-archive
For each archive mentioned on the command line after the --whole-archive option, include every object file in the
archive in the link, rather than searching the archive for the required object files. This is normally used to turn
an archive file into a shared library, forcing every object to be included in the resulting shared library. This
option may be used more than once.
(gcc -Wl,--whole-archive)
Plus, you should put -Wl,--no-whole-archive at the end of the library list. (as said by Dmitry Yudakov in the comment below)

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

dynamic library loading with linking to static library

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.