LD_PRELOAD doesn't affect dlopen() with RTLD_NOW - c

If I use a function from a shared library directly, i.e. by declaring it in my code and linking during compile time, LD_PRELOAD works fine. But if I use dlopen()/dlsym() instead LD_PRELOAD has no effect!
The problem is that I want to debug a program that loads some plugins using dlopen(), and it uses absolute file names at that, so simply using LD_LIBRARY_PATH won't work.
Here's a sample code which illustrates the problem.
./libfoo.so
void foo() {
printf("version 1\n");
}
./preload/libfoo.so
void foo() {
printf("version 2\n");
}
main.c
#include <stdio.h>
#include <dlfcn.h>
void foo();
int main(int argc, char *argv[]) {
void (*pfoo)();
foo(); // call foo() first so we are sure ./preload/libfoo.so is loaded when we call dlopen()
pfoo = dlsym(dlopen("libfoo.so", RTLD_NOW), "foo");
pfoo();
return 0;
}
command line
LD_PRELOAD=preload/libfoo.so LD_LIBRARY_PATH=. ./a.out
output
version 2
version 1
Why doesn't LD_PRELOAD affect dlopen(), and is there any way to redirect dlopen(), especially when using absolute paths?

Specifying LD_PRELOAD will cause the loader to unconditionally load (and initialize) the indicated shared libraries prior to loading the main executable. This makes the symbols defined in the preloaded libraries available prior to linking main, allowing the interposition of symbols. [Note 1]
So, in your example, the call to foo() uses the symbol from the preloaded module, and dlsym would return the same symbol if you had called it with a NULL handle.
However, the call to dlopen does not take into account the symbol you are looking for (for obvious reasons). It just loads the indicated shared object or returns a handle to an already-cached version of the shared object. It does not add the module to a list of modules to load if necessary; it simply loads the module. And when you pass the returned handle to dlsym, dlsym looks in precisely that module in order to resolve the symbol, rather than searching the set of external symbols present in the executable. [Note 2]
As I mentioned, dlopen will not load the "same" shared object more than once, if it already has loaded the object. [Note 3]. However, the shared object in your LD_PRELOAD is called preload/libfoo.so, not libfoo.so. (ELF does not strip directory paths from shared object names, unlike certain other operating systems.) So when you call dlopen("libfoo.so"), the dynamic loader is not going to find any shared object named libfoo.so in the cache of loaded shared objects, and it will therefore look for that object in the filesystem, using the library search paths since the provided filename does not contain a /.
As it turns out, ELF does allow you to specify the name of a shared object. So you can set the name of the preloaded module to the name which you will later dynamically load, and then dlopen will return the handle to the preloaded module.
We start by correcting the version of main.c in the original question:
#include <stdio.h>
#include <dlfcn.h>
void foo();
int main(int argc, char *argv[]) {
const char* soname = argc > 1 ? argv[1] : "libfoo.so";
void (*pfoo)();
pfoo = dlsym(NULL, "foo"); // Find the preloaded symbol, if any.
if (pfoo) pfoo(); else puts("No symbol foo before dlopen.");
void* handle = dlopen(soname, RTLD_NOW);
if (handle) {
pfoo = dlsym(handle, "foo"); // Find the symbol in the loaded SO
if (pfoo) pfoo(); else puts("No symbol foo after dlopen.");
}
else puts("dlopen failed to find the shared object.");
return 0;
}
This can be built without specifying any libraries other than libdl:
gcc -Wall -o main main.c -ldl
If we build the two shared libraries with no specified names, which is probably what you did:
gcc -Wall -o libfoo.so -shared -fPIC libfoo.c
gcc -Wall -o preload/libfoo.so -shared -fPIC preload/libfoo.c
then we observe that the dlopen/dlsym finds the symbol in the loaded module:
$ LD_PRELOAD=preload/libfoo.so LD_LIBRARY_PATH=. ./main libfoo.so
version 2
version 1
However, if we assign the name being looked for to the preloaded shared object, we get a different behaviour:
$ gcc -Wall -o preload/libfoo.so -Wl,--soname=libfoo.so -shared -fPIC preload/libfoo.c
$ LD_PRELOAD=preload/libfoo.so LD_LIBRARY_PATH=. ./main libfoo.so
version 2
version 2
That works because the dlopen is looking for the shared object named libfoo.so. However, it is more likely that an application loading plugins will use a filename rather than using the library search path. And that will cause the preloaded shared object to not be considered, because the names no longer match:
$ LD_PRELOAD=preload/libfoo.so LD_LIBRARY_PATH=. ./main ./libfoo.so
version 2
version 1
As it happens, we can make this work by building the shared library with the name actually being looked for:
$ gcc -Wall -o preload/libfoo.so -Wl,--soname=./libfoo.so -shared -fPIC preload/libfoo.c
$ LD_PRELOAD=preload/libfoo.so LD_LIBRARY_PATH=. ./main libfoo.so
version 2
version 2
That's a bit of a hack, IMHO, but it is acceptable for debugging. [Note 4]
Notes:
Consequently, the comment "call foo() first so we are sure ./preload/libfoo.so is loaded" is incorrect; the preloaded module is preloaded, not added to a list of modules to load if necessary.
If you want dlsym to just look for a symbol, you can pass a NULL handle. In that case, dlsym will search in modules loaded by dlopen (including modules required by the module loaded by dlopen). But that's rarely what you want, since applications which load plugins with dlsym normally specify a particular symbol (or symbols) which the plugin must define, and these symbols will be present in every loaded plugin, making the lookup by symbol name imprecise.
This is not quite correct, but dynamic symbol namespaces are outside the scope of this answer.
Other hacks are possible, of course. You could, for example, interpose your own version of dlopen to override the shared object name lookup. But that's probably a lot more work than necessary.

According to http://linux.die.net/man/3/dlopen
The four functions dlopen(), dlsym(), dlclose(), dlerror() implement
the interface to the dynamic linking loader.
Whereas the LD_PRELOAD only affects the dynamic linker itself -- ie: ld.so (http://linux.die.net/man/8/ld.so). The only way I can think of forcing dlopen to resolve as you want is through chroot.
Followup thought:
Another thought I just had, what if you write a wrapper that FIRST loads the correct *.so THEN invokes the program you are trying to redirect. Does this cause the child process to use the redirected *.so ?

The problem is that I want to debug a program that loads some plugins using dlopen(), and it uses absolute file names at that, so simply using LD_LIBRARY_PATH won't work.
Yep, dlopen does not do LD_LIBRARY_PATH search for paths with slashes.
You can override/superimpose dlopen itself to do that search for those specific plug-in paths.

Related

When to actually use dlopen()? Does dlopen() means dynamic loading?

I have gone through below link, through which I understood how to create and use shared library.
https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
Step 1: Compiling with Position Independent Code
$ gcc -c -Wall -Werror -fpic foo.c
Step 2: Creating a shared library from an object file
$ gcc -shared -o libfoo.so foo.o
Step 3: Linking with a shared library
$ gcc -L/home/username/foo -Wall -o test main.c -lfoo
Step 4: Making the library available at runtime
$ export LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH
$ ./test
This is a shared library test...
Hello, I am a shared library
However, I have couple of questions:
In the given link, there is no usage of dlopen(), which is required to open shared library. How this code is working without dlopen() calls?
When to actually use dlopen()?
Can I compile program without having .so file available (program has function calls to that shared library)?
Does the dlopen() means dynamic loading and example in above link(step 3) means static loading? If Yes, then in case of dynamic loading, is there any difference in linking step(step 3)?
Thanks in advance.
Dynamic Library
When we link an application against a shared library, the linker leaves some stubs (unresolved symbols) to be filled at application loading time. These stubs need to be filled by a tool called, dynamic linker at run time or at application loading time.
Loading of a shared library is of two types,
Dynamically linked libraries –
Here a program is linked with the shared library and the kernel loads the library (in case it’s not in memory) upon execution.
This is explained in mentioned link.
Dynamically loaded libraries –
Useful for creating a "plug-in" architecture.
As the name indicates, dynamic loading is about loading of library on demand and linked during execution.
The program takes full control by calling functions with the library.
This is done using dlopen(), dlsym(), dlclose().
The dlopen() function opens a library and prepares it for use.
With this system call it is possible to open a shared library and use the functions from it, without having to link with it. Your program just starts, and when it finds out that it needs to use a function from a specific library, it calls dlopen() to open that library. If the library is not available on the system, the function returns NULL and it is up to you, the programmer, to handle that. You can let the program gracefully die.
DL Example:
This example loads the math library and prints the cosine of 2.0, and it checks for errors at every step (recommended):
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen ("/lib/libm.so.6", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
}
Use -rdynamic while compiling DL source code.
Ex. gcc -rdynamic -o progdl progdl.c -ldl

On linking of shared libraries, are they really final, and if so, why?

I am trying to understand more about linking and shared library.
Ultimately, I wonder if it's possible to add a method to a shared library. For instance, suppose one has a source file a.c, and a library lib.so (without the source file). Let's furthermore assume, for simplicity, that a.c declares a single method, whose name is not present in lib.so. I thought maybe it might be possible to, at linking time, link a.o to lib.so while instructing to create newLib.so, and forcing the linker to export all methods/variable in lib.so to that the newLib.so is now basically lib.so with the added method from a.so.
More generally, if one has some source file depending on a shared library, can one create a single output file (library or executable) that is not dependent on the shared library anymore ? (That is, all the relevant methods/variable from the library would have been exported/linked/inlined to the new executable, hence making the dependency void). If that's not possible, what is technically preventing it ?
A somehow similar question has been asked here: Merge multiple .so shared libraries.
One of the reply includes the following text: "If you have access to either source or object files for both libraries, it is straightforward to compile/link a combined SO from them.: without explaining the technical details. Was it a mistake or does it hold ? If so, how to do it ?
Once you have a shared library libfoo.so the only ways you can use it
in the linkage of anything else are:-
Link a program that dynamically depends on it, e.g.
$ gcc -o prog bar.o ... -lfoo
Or, link another shared library that dynamically depends on it, e.g.
$ gcc -shared -o libbar.so bar.o ... -lfoo
In either case the product of the linkage, prog or libbar.so
acquires a dynamic dependency on libfoo.so. This means that prog|libfoo.so
has information inscribed in it by the linker that instructs the
OS loader, at runtime, to find libfoo.so, load it into the
address space of the current process and bind the program's references to libfoo's exported symbols to
the addresses of their definitions.
So libfoo.so must continue to exist as well as prog|libbar.so.
It is not possible to link libfoo.so with prog|libbar.so in
such a way that libfoo.so is physically merged into prog|libbar.so
and is no longer a runtime dependency.
It doesn't matter whether or not you have the source code of the
other linkage input files - bar.o ... - that depend on libfoo.so. The
only kind of linkage you can do with a shared library is dynamic linkage.
This is in complete contrast with the linkage of a static library
You wonder about the statement in this this answer where it says:
If you have access to either source or object files for both libraries, it is straightforward to compile/link a combined SO from them.
The author is just observing that if I have source files
foo_a.c foo_b.c... bar_a.c bar_b.c
which I compile to the corresponding object files:
foo_a.o foo_b.o... bar_a.o bar_b.o...
or if I simply have those object files. Then as well as - or instead of - linking them into two shared libraries:
$ gcc -shared -o libfoo.so foo_a.o foo_b.o...
$ gcc -shared -o libbar.so bar_a.o bar_b.o...
I could link them into one:
$ gcc -shared -o libfoobar.so foo_a.o foo_b.o... bar_a.o bar_b.o...
which would have no dependency on libfoo.so or libbar.so even if they exist.
And although that could be straightforward it could also be false. If there is
any symbol name that is globally defined in any of foo_a.o foo_b.o... and
also globally defined in any of bar_a.o bar_b.o... then it will not matter
to the linkage of either libfoo.so or libbar.so (and it need not be dynamically
exported by either of them). But the linkage of libfoobar.so will fail for
multiple definition of name.
If we build a shared library libbar.so that depends on libfoo.so and has
itself been linked with libfoo.so:
$ gcc -shared -o libbar.so bar.o ... -lfoo
and we then want to link a program with libbar.so, we can do that in such a way
that we don't need to mention its dependency libfoo.so:
$ gcc -o prog main.o ... -lbar -Wl,-rpath=<path/to/libfoo.so>
See this answer to follow that up. But
this doesn't change the fact that libbar.so has a runtime dependency on libfoo.so.
If that's not possible, what is technically preventing it?
What technically prevents linking a shared library with some program
or shared library targ in a way that physically merges it into targ is that a
shared library (like a program) is not the sort of thing that a linker knows
how to physically merge into its output file.
Input files that the linker can physically merge into targ need to
have structural properties that guide the linker in doing that merging. That is the structure of object files.
They consist of named input sections of object code or data that are tagged with various attributes.
Roughly speaking, the linker cuts up the object files into their sections and distributes them into
output sections of the output file according to their attributes, and makes
binary modifications to the merged result to resolve static symbol references
or enable the OS loader to resolve dynamic ones at runtime.
This is not a reversible process. The linker can't consume a program or
shared library and reconstruct the object files from which it was made to
merge them again into something else.
But that's really beside the point. When input files are physically
merged into targ, that is called static linkage.
When input files are just externally referenced in targ to
make the OS loader map them into a process it has launched for targ,
that is called dynamic linkage. Technical development has given us
a file-format solution to each of these needs: object files for static linkage, shared libraries
for dynamic linkage. Neither can be used for the purpose of the other.

How to run c program with .so file

I have gone through all the solutions on StackOverflow as well as Ask Ubuntu.
I have a Go program:
package main
import "C"
//export Getint
func Getint() int {
return 2
}
func main() {}
and I have generated .so file for the same with name t.so and header filet.h`
Now I would like to use this function in my C program.
I have written the code but I don't know how to execute it.
#include <stdio.h>
#include <t.h>
int main()
{
int a;
a=Getint();
printf("number : %d",a);
return 0;
}
When I execute it with
gcc c.c t.so
it generates a.out file
but at the time of running a.out with ./a.out it gives an error:
./a.out
Error while loading shared libraries: t.so: can not open shared object file: no such file or directory exists.
then I tried with:
gcc -c c.c -l t.so
So it generates c.o file and it is not executable.
You should use the linker option -rpath, which tells the linker to add information in the executable program where to find runtime libraries like your .so file.
This can be done using the GCC option -Wl which instructs the GCC frontend program to pass an option to the linker:
$ gcc c.c t.so -Wl,-rpath=$(pwd)
This will pass -rpath=$(pwd) to the linker, and $(pwd) causes the shell to call the pwd command to return the current directory.
As long as you don't move the library the program should work.
You can use the environment variable LD_LIBRARY_PATH too, but it's not recommended.
Most probably your loader cannot find the library. Try to put the path to the directory where the libarry is located to LD_LIBRARY_PATH prior to run your binary.
export LD_LIBRARY_PATH=/path/to/my/library
./a.out
.so files are shared object, meaning object that are available to all applications that need them.. that is, shared. Due to this characteristics, they need to be stored in a well known place. Also, they need to be indexed by the dynamic linker.
In linux for instance you typically have a file /etc/ld.so.conf where all directories where shared object are automatically read from are stored
So your options are:
Put your shared object file in a well known place
Put your shared object file in a place of your choice and let the dynamic linker know about it: in linux you can modify ld.so.conf and run ldconfig to update ld indexes
As other suggested write the path of your .so in the env variable LD_LIBRARY_PATH (since dynamic linker reads it before running your application). This must be done at each environment creation
As other suggested use -rpath when compiling. Note that in this way you cannot move your .so file after the compilation
Personally I prefer installing the .so file in a system library path
You should use LD_LIBRARY_PATH to let the dynamic linker find your shared library in the list. Syntax is similar to PATH a list of directories separted by :.
On OSX this environment variable is called DYLD_LIBRARY_PATH.

How does this C program compile and run with two main functions?

Today, while working with one custom library, I found a strange behavior.
A static library code contained a debug main() function. It wasn't inside a #define flag. So it is present in library also. And it is used link to another program which contained the real main().
When both of them are linked together, the linker didn't throw a multiple declaration error for main(). I was wondering how this could happen.
To make it simple, I have created a sample program which simulated the same behavior:
$ cat prog.c
#include <stdio.h>
int main()
{
printf("Main in prog.c\n");
}
$ cat static.c
#include <stdio.h>
int main()
{
printf("Main in static.c\n");
}
$ gcc -c static.c
$ ar rcs libstatic.a static.o
$ gcc prog.c -L. -lstatic -o 2main
$ gcc -L. -lstatic -o 1main
$ ./2main
Main in prog.c
$ ./1main
Main in static.c
How does the "2main" binary find which main to execute?
But compiling both of them together gives a multiple declaration error:
$ gcc prog.c static.o
static.o: In function `main':
static.c:(.text+0x0): multiple definition of `main'
/tmp/ccrFqgkh.o:prog.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
Can anyone please explain this behavior?
Quoting ld(1):
The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive.
When linking 2main, main symbol gets resolved before ld reaches -lstatic, because ld picks it up from prog.o.
When linking 1main, you do have undefined main by the time it gets to -lstatic, so it searches the archive for main.
This logic only applies to archives (static libraries), not regular objects.
When you link prog.o and static.o, all symbols from both objects are included unconditionally, so you get a duplicate definition error.
When you link a static library (.a), the linker only searches the archive if there were any undefined symbols tracked so far. Otherwise, it doesn't look at the archive at all. So your 2main case, it never looks at the archive as it doesn't have any undefined symbols for making the translation unit.
If you include a simple function in static.c:
#include <stdio.h>
void fun()
{
printf("This is fun\n");
}
int main()
{
printf("Main in static.c\n");
}
and call it from prog.c, then linker will be forced to look at the archive to find the symbol fun and you'll get the same multiple main definition error as linker would find the duplicate symbol main now.
When you directly compile the object files(as in gcc a.o b.o), the linker doesn't have any role here and all the symbols are included to make a single binary and obviously duplicate symbols are there.
The bottom line is that linker looks at the archive only if there are missing symbols. Otherwise, it's as good as not linking with any libraries.
After the linker loads any object files, it searches libraries for undefined symbols. If there are none, then no libraries need to be read. Since main has been defined, even if it finds a main in every library, there is no reason to load a second one.
Linkers have dramatically different behaviors, however. For example, if your library included an object file with both main () and foo () in it, and foo was undefined, you would very likely get an error for a multiply defined symbol main ().
Modern (tautological) linkers will omit global symbols from objects that are unreachable - e.g. AIX. Old style linkers like those found on Solaris, and Linux systems still behave like the unix linkers from the 1970s, loading all of the symbols from an object module, reachable or not. This can be a source of horrible bloat as well as excessive link times.
Also characteristic of *nix linkers is that they effectively search a library only once for each time it is listed. This puts a demand on the programmer to order the libraries on the command line to a linker or in a make file, in addition to writing a program. Not requiring an ordered listing of libraries is not modern. Older operating systems often had linkers that would search all libraries repeatedly until a pass failed to resolve a symbol.

Multiple definition of a symbol while building a shared library with static libraries

I have to build a single shared library from multiple object files. Lets say object file Obj1.o and Obj2.o kept under obj_folder and both use a common function foo(). function foo() is defined in another cpp file lets call it foo.cpp. The ibject of foo.cpp is also present under obj_folder.
Scenario is as below:
In obj1.cpp
void func1()
{
int timestamp =foo();
}
in obj2.cpp
void func2()
{
int timestamp = foo();
}
Both files have their obj1.o and obj2.o build separately. What my thinking here is both obj1.o and obj2.o have statically build code for foo() and while in building linker just cant find from which object it should pick foo() location.
building shared object project.so i use following command -
gcc -shared -fPIC obj_folder/*.o -o project.so
building shared object i see error message -
Multiple definition of foo()
How i can resolve this symbol collision and build my shared librray?
Multiple definition of foo()
How i can resolve this symbol collision and build my shared librray?
Unfortunately you have not provided enough info to answer that question.
Your description appears to imply that foo is defined in foo.o, but if that was so, you wouldn't get the link error you are getting.
The first step is therefore to find out where foo is actually defined. Here is the recipe to do so:
nm -A obj_folder/*.o | grep ' foo$'
For the link error to make sense, there should be two separate .o files with foo defined in each one. When linking you library, you'll have to get rid of one of them.
P.S. Don't call directories a "folder".
P.P.S. Linking a library like so: gcc ... obj_folder/*.o -o project.so is a really bad idea(TM). Learn and use make.

Resources