[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
On machines which do not have any facility for shared libraries or
dynamic modules, libltdl allows an application to
lt_dlopen
modules, provided that the modules are known at link
time. This works by linking the code for the modules into the
application in advance, and then looking up the addresses of the already
loaded symbols when lt_dlsym
is called. We call this mechanism
dlpreopening – so named because the modules must be loaded at
link time, not because the API to use modules loaded in this way is
any different.
This feature is extremely useful for debugging, allowing you to make a fully statically linked application from the executable and module objects, without changing any source code to work around the module loading calls. As far as the code outside the libltdl API can tell, these modules really are being loaded dynamically. Driving a symbolic debugger across module boundaries is however much easier when blocks of code aren’t moving in and out of memory during execution.
You may have wondered about the purpose of the following line in the dynamic module code in Dependent Libraries:
#define run ltdl_module_LTX_run |
The reason for redefining the entry point symbol in this way is to
prevent a symbol clash when two or more modules that provide
identically named entry point functions are preloaded into an
executable. It would be otherwise impossible to preload both
‘simple-module.c’ and ‘ltdl-module.c’, for example, since
each defines the symbol ‘run’. To allow us to write dynamic
modules that are potentially preloaded, lt_dlsym
will first try
to lookup the address of a named symbol with a prefix consisting of the
canonicalized name of the module being searched, followed by the
characters ‘_LTX_’. The module name part of this prefix is
canonicalized by replacing all non-alphanumeric characters with an
underscore. If that fails, lt_dlsym
resorts to the unadorned
symbol name, which is how ‘run’ was found in
‘simple-module.la’ by ‘ltdl-loader’ earlier.
Supporting this feature in your module loading code is a simple matter of initialising the address lookup table, and ‘ltdl.h’ defines a convenient macro to do exactly that:
Add this macro to the code of your module loading code, before the first call to a libltdl function, to ensure that the dlopen address lookup table is populated.
Now change the contents of ‘ltdl-loader.c’, and add a call to this macro, so that it looks like this:
/* Initialise preloaded symbol lookup table. */ LTDL_SET_PRELOADED_SYMBOLS(); /* Initialise libltdl. */ errors = lt_dlinit (); |
Libtool will now be able to fall back to using preloaded static modules if you tell it to, or if the host platform doesn’t support native dynamic loading.
If you use ‘LTDL_SET_PRELOADED_SYMBOLS’ in your module loader, you must also specify something to preload to avoid compilation failure due to undefined ‘lt_preloaded_symbols’. You can name modules on the Libtool link command line using one of ‘-dlopen’ or ‘-dlpreopen’. This includes support for accessing the symbols of the main executable opened with ‘lt_dlopen(NULL)’—you can ask Libtool to fall back to preopening the main modules like this:
$ libtool gcc -g -o ltdl-loader -dlopen self -rpath /tmp/lib \ ltdl-loader.c -lltdl rm -f .libs/ltdl-loader.nm .libs/ltdl-loader.nmS \ .libs/ltdl-loader.nmT creating .libs/ltdl-loaderS.c (cd .libs && gcc -c -fno-builtin -fno-rtti -fno-exceptions "ltdl-loaderS.c") rm -f .libs/ltdl-loaderS.c .libs/ltdl-loader.nm .libs/ltdl-loader.nmS .libs/ltdl-loader.nmT gcc -o ltdl-loader .libs/ltdl-loaderS.o ltdl-loader.c -Wl,--export-dynamic /usr/lib/libltdl.so -ldl -Wl,--rpath -Wl,/tmp/lib rm -f .libs/ltdl-loaderS.oIt doesn’t make sense to add preloaded module support to a project, when you have no modules to preopen, so the compilation failure in that case is actually a feature of sorts.
The ‘LTDL_SET_PRELOADED_SYMBOLS’ macro does not interfere with the normal operation of the code when modules are dynamically loaded, provided you use the ‘-dlopen’ option on the link line. The advantage of referencing the macro by default is that you can recompile the application with or without preloaded module, and all without editing the sources.
If you have no modules to link in by default, you can force Libtool to populate the preload symbol table by using the ‘-dlopen force’ option. This is the option used to preload the symbols of the main executable so that you can subsequently call ‘lt_dlopen(NULL)’.
Multiple modules can be preloaded, although at the time of writing only Libtool compiled modules can be used. If there is a demand, Libtool will be extended to include native library preloading in a future revision.
To illustrate, I have recompiled the ‘simple-module.c’ module with
libtool
:
$ libtool --mode=compile gcc -c simple-module.c rm -f .libs/simple-module.lo gcc -c simple-module.c -fPIC -DPIC -o .libs/simple-module.lo gcc -c simple-module.c -o simple-module.o >/dev/null 2>&1 mv -f .libs/simple-module.lo simple-module.lo $ libtool --mode=link gcc -g -o simple-module.la -rpath `pwd` -no-undefined -module -avoid-version simple-module.lo rm -fr .libs/simple-module.la .libs/simple-module.* .libs/simple-module.* gcc -shared simple-module.lo -lc -Wl,-soname \ -Wl,simple-module.so -o .libs/simple-module.so ar cru .libs/simple-module.a simple-module.o creating simple-module.la (cd .libs && rm -f simple-module.la && ln -s ../simple-module.la \ simple-module.la) |
The names of the modules that may be subsequently lt_dlopen
ed are
added to the application link line. I am using the ‘-static’
option to force a static only link, which must use dlpreopened modules
by definition. I am only specifying this because my host has native
dynamic loading, and Libtool will use that unless I force a static only
link, like this:
$ libtool --mode=link gcc -static -g -o ltdl-loader ltdl-loader.c \ -lltdl -dlopen ltdl-module.la -dlopen simple-module.la rm -f .libs/ltdl-loader.nm .libs/ltdl-loader.nmS \ .libs/ltdl-loader.nmT creating .libs/ltdl-loaderS.c extracting global C symbols from ./.libs/ltdl-module.a extracting global C symbols from ./.libs/simple-module.a (cd .libs && gcc -c -fno-builtin -fno-rtti -fno-exceptions \ "ltdl-loaderS.c") rm -f .libs/ltdl-loaderS.c .libs/ltdl-loader.nm \ .libs/ltdl-loader.nmS .libs/ltdl-loader.nmT gcc -g -o ltdl-loader ltdl-loader.c .libs/ltdl-loaderS.o \ ./.libs/ltdl-module.a -lm ./.libs/simple-module.a \ /usr/lib/libltdl.a -ldl rm -f .libs/ltdl-loaderS.o $ ./ltdl-loader ltdl-module 345 Square root of 345 is 18.574176 => 0 $ ./ltdl-loader simple-module World Hello, World! => 0 |
Note that the current release of Libtool requires that the pseudo-library be present for any libltdl loaded module, even preloaded ones. Once again, if there is sufficient demand, this may be fixed in a future release. Until then, if the pseudo-library was deleted or cannot be found, this will happen:
$ rm -f simple-module.la $ ./ltdl-loader simple-module World ./ltdl-loader: file not found. |
A side effect of using the ‘LTDL_SET_PRELOADED_SYMBOLS’ macro is that if you subsequently link the application without Libtool, you will get an undefined symbol for the Libtool supplied ‘lt_preloaded_symbols’. If you need to link in this fashion, you will need to provide a stub that supplies the missing definition. Conversely, you must be careful not to link the stub file when you do link with Libtool, because it will clash with the Libtool generated table it is supposed to replace:
#include <ltdl.h> const lt_dlsymlist lt_preloaded_symbols[] = { { 0, 0 } }; |
Of course, if you use this stub, and link the application without the benefits of Libtool, you will not be able to use any preloaded modules – even if you statically link them, since there is no preloaded symbol lookup table in this case.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by Ben Elliston on July 10, 2015 using texi2html 1.82.