Using filter objects instead of dlopen()?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

In order to avoid hard requiring certain optional libraries, systemd started to use dlopen(). From the top of my head dlopen has several disadvantages, eg
- need to duplicate function prototypes in your own code
- need to have (macro)code to load all symbols you need
- you hardly notice when the library changes, both API and ABI wise
- it's easy to make mistakes when the library uses symbol versioning
- tools like ldd don't show what libs you may use

So while dlopen is fine to load plugins with an interface you define yourself, it's not all that great to load system libraries IMO.

There's a rather under-documented ld feature that may be useful instead: filter objects using DT_AUXILIARY¹. The idea of that is to have shared libraries that define names of other shared libraries that can overload the original symbols with alternative implementations. ld does the linking magic for you, no code changes needed.

That also works the other way around. So you could write a stub library that would specify the original library as alternative implementation. If the original is there it would be used, otherwise your stubs would be called. As long as you don't actually call the stubs they do not need to have a meaningful prototype nor content. So that works best for libraries that have some init function that can return error. Then you'd just have to reimplement the init function in the stub lib, use a boilerplate for the rest and make sure no other symbol is used in case of initialization error.

Somehow I figured that stuff out ages ago in a toy project. There's a script to generate stub functions that just segfault when called as well as a linker map given the path to a shared library:
https://github.com/XQF/xqf/blob/0c68cf75fc65eabdfa3e44ff45696f1ba56284fd/src/gensyms.pl

The init functions need reimplementation but one can include the original header of course to make sure the prototype is correct:
https://github.com/XQF/xqf/blob/0c68cf75fc65eabdfa3e44ff45696f1ba56284fd/src/libxqf_dummy_GeoIP_stubs.c

In that case the main program would only link against libxqf_dummy_GeoIP.so.0 (probably in a private location).
That dummy library is produced using something like
-nostdlib -shared -Wl,-f,libGeoIP.so.0 -Wl,-soname,libxqf_dummy_GeoIP.so.0

So DT_AUXILIARY is set to the soname of the original lib as determined during build.

What I don't know is whether DT_AUXILIARY is just some exotic misfeature or actually considered a good idea. AFAIK that stuff worked fine in XQF back then. YMMV, just wanted to mention it as it that feature is not widely known. Maybe someone is curious enough to give it a try. Or find arguments why dlopen is still the lesser evil for the sake of documenting that for the future :-)

cu
Ludwig

[1] https://manpages.opensuse.org/Tumbleweed/binutils/ld.1.en.html#auxiliary=

--
 (o_   Ludwig Nussel
 //\
 V_/_  http://www.suse.com/
SUSE Software Solutions Germany GmbH, GF: Ivo Totev
HRB 36809 (AG Nürnberg)



[Index of Archives]     [LARTC]     [Bugtraq]     [Yosemite Forum]     [Photo]

  Powered by Linux