linux dlopen: can a library be notified when it is loaded?
Libraries should export initialization
and cleanup routines using the gcc
__attribute__((constructor)) and __attribute__((destructor)) function attributes. See the gcc info pages for
information on these. Constructor
routines are executed before dlopen
returns (or before main() is started
if the library is loaded at load
time). Destructor routines are
executed before dlclose returns (or
after exit() or completion of main()
if the library is loaded at load
time). The C prototypes for these
functions are:
void __attribute__ ((constructor)) my_init(void);
void __attribute__ ((destructor)) my_fini(void);
Taken from http://tldp.org/HOWTO/Program-Library-HOWTO/index.html
THat is, you just tack on __attribute__ ((constructor)) to the functions you want to be called when the shared library is loaded. The above docuemtn also notes that the older _ini and _fini functions are considered obsolete.
C++ linux: dlopen can't find .so library
Read the dlopen(3) man page (e.g. by typing man dlopen
in a terminal on your machine):
If filename contains a slash ("/"), then it
is interpreted as a (relative or absolute) pathname. Otherwise, the
dynamic linker searches for the library as follows (see ld.so(8) for
further details):
o (ELF only) If the executable file for the calling program
contains a DT_RPATH tag, and does not contain a DT_RUNPATH tag,
then the directories listed in the DT_RPATH tag are searched.
o If, at the time that the program was started, the environment
variable LD_LIBRARY_PATH was defined to contain a colon-separated
list of directories, then these are searched. (As a security
measure this variable is ignored for set-user-ID and set-group-ID
programs.)
o (ELF only) If the executable file for the calling program
contains a DT_RUNPATH tag, then the directories listed in that
tag are searched.
o The cache file /etc/ld.so.cache (maintained by ldconfig(8)) is
checked to see whether it contains an entry for filename.
o The directories /lib and /usr/lib are searched (in that order).
So you need to call dlopen("./libLibraryName.so", RTLD_NOW)
-not just dlopen("libLibraryName.so", RTLD_NOW)
which wants your plugin to be in your $LD_LIBRARY_PATH
on in /usr/lib/
etc .... - or add .
to your LD_LIBRARY_PATH
(which I don't recommend for security reasons).
As Jhonnash answered you should use and display the result of dlerror
when dlopen
(or dlsym
) fails:
void* dlh = dlopen("./libLibraryName.so", RTLD_NOW);
if (!dlh)
{ fprintf(stderr, "dlopen failed: %s\n", dlerror());
exit(EXIT_FAILURE); };
You might want to read some books like Advanced Linux Programming to get some knowledge about Linux system programming in general.
Is there a load leak if dlopen() is called from a dlopen'd library?
The application need only worry about what the app loads directly. If you load a.so
, all you need to be concerned with is unloading a.so
.
If a.so
refuses to unload b.so
, that is a problem with a.so
, your app is not responsible for this. The author of a.so
needs to get their act together and fix the problem with their library.
Linux and shared libraries, linking vs dlopen - symbol visibility
Your question is exceedingly unclear.
If you dlopen
the library, then about the only way to get to any of its symbols is via dlsym
.
However, if you dlopen
a library with RTLD_GLOBAL
, then its symbols become available for subsequently loaded libraries without using dlsym
.
For example, if libfoo.so
defines symbol foo
, and if you dlopen("libfoo.so", RTLD_GLOBAL|...);
and later dlopen("libbar.so", ...)
which uses foo
, that would work -- libbar.so
will be able to use foo
from libfoo.so
without doing any dlsym
calls.
Why would dlopen reuse the address of a previously loaded symbol?
The key to answering this question is whether the main executable exports the same symbol in its dynamic symbol table. That is, what is the output from:
nm -D a.out | grep ' mangled_name_of_the_symbol'
If the output is empty, the two libraries should indeed use separate (their own) copies of the symbol. But if the output is not empty, then both libraries should reuse the symbol defined in the main binary (this happens because UNIX dynamic linking attempts to emulate what would have happened if everything was statically linked into the main binary -- UNIX support for shared libraries happened long after UNIX itself became popular, and in that context this design decision made sense).
Demonstration:
// main.c
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
int foo = 12;
int main()
{
printf("main: &foo = %p, foo = %d\n", &foo, foo);
void *h = dlopen("./foo.so", RTLD_NOW);
assert (h != NULL);
void (*fn)(void) = (void (*)()) dlsym(h, "fn");
fn();
return 0;
}
// foo.c
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
int foo = 42;
void fn()
{
printf("foo: &foo = %p, foo = %d\n", &foo, foo);
void *h = dlopen("./bar.so", RTLD_NOW);
assert (h != NULL);
void (*fn)(void) = (void (*)()) dlsym(h, "fn");
fn();
}
// bar.c
#include <stdio.h>
int foo = 24;
void fn()
{
printf("bar: &foo = %p, foo = %d\n", &foo, foo);
}
Build this with:
gcc -fPIC -shared -o foo.so foo.c && gcc -fPIC -shared -o bar.so bar.c &&
gcc main.c -ldl && ./a.out
Output:
main: &foo = 0x5618f1d61048, foo = 12
foo: &foo = 0x7faad6955040, foo = 42
bar: &foo = 0x7faad6950028, foo = 24
Now rebuild just the main binary with -rdynamic
(which causes foo
to be exported from it): gcc main.c -ldl -rdynamic
. The output changes to:
main: &foo = 0x55ced88f1048, foo = 12
foo: &foo = 0x55ced88f1048, foo = 12
bar: &foo = 0x55ced88f1048, foo = 12
P.S.
You can gain much insight into the behavior of dynamic linker by running with:
LD_DEBUG=symbols,bindings ./a.out
Update:
It turns out I asked a wrong question ... Added source example.
If you look at LD_DEBUG
output, you'll see:
165089: symbol=object; lookup in file=./main [0]
165089: symbol=object; lookup in file=./liba.so [0]
165089: binding file ./liba.so [0] to ./liba.so [0]: normal symbol `object'
165089: symbol=object; lookup in file=./main [0]
165089: symbol=object; lookup in file=./liba.so [0]
165089: binding file ./libb.so [0] to ./liba.so [0]: normal symbol `object'
What this means: liba.so
is in the global search list (by virtue of having been directly linked to by main
). This is approximately equivalent to having done dlopen("./liba.so", RTLD_GLOBAL)
.
It should not be a surprise then that the symbols in it are available for subsequently loaded shared libraries to bind to, which is exactly what the dynamic loader does.
Related Topics
Is It Possible That Linux File Descriptor 0 1 2 Not for Stdin, Stdout and Stderr
How to Get Started Developing on *Nix
Encrypt a String Using Openssl Command Line
Installing R from Cran Ubuntu Repository: No Public Key Error
Error with Gradlew: /Usr/Bin/Env: Bash: No Such File or Directory
The Irq in Kernel Function Asm_Do_Irq() Is Different from the One I Request in Module
Moving Multiple Files Having Spaces in Name (Linux)
Differencebetween './Example.Sh' and 'Sh Example.Sh'
How to Look Up a Variable by Name with #!/Bin/Sh (Posix Sh)
How to Run Dos2Unix on an Entire Directory
How to See Top Processes Sorted by Actual Memory Usage
How to Calculate an Md5 Checksum of a Directory
How to Tell Whether I'm in a Screen
Swift on Os X Compiling for Linux
Centos Through a Vm - No Urls in Mirrorlist
Why Is Dd with the 'Direct' (O_Direct) Flag So Dramatically Faster