What is the LD_PRELOAD trick? - c

I came across a reference to it recently on proggit and (as of now) it is not explained.
I suspect this might be it, but I don't know for sure.

If you set LD_PRELOAD to the path of a shared object, that file will be loaded before any other library (including the C runtime, libc.so). So to run ls with your special malloc() implementation, do this:
$ LD_PRELOAD=/path/to/my/malloc.so /bin/ls

You can override symbols in the stock libraries by creating a library with the same symbols and specifying the library in LD_PRELOAD.
Some people use it to specify libraries in nonstandard locations, but LD_LIBRARY_PATH is better for that purpose.

As many people mentioned, using LD_PRELOAD to preload library. By the way, you can CHECK if the setting is available by ldd command.
Example: Suppose you need to preload your own libselinux.so.1.
> ldd /bin/ls
...
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f3927b1d000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f3927914000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f392754f000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f3927311000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f392710c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3927d65000)
libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f3926f07000)
Thus, set your preload environment:
export LD_PRELOAD=/home/patric/libselinux.so.1
Check your library again:
>ldd /bin/ls
...
libselinux.so.1 =>
/home/patric/libselinux.so.1 (0x00007fb9245d8000)
...

With LD_PRELOAD you can give libraries precedence.
For example you can write a library which implement malloc and free. And by loading these with LD_PRELOAD your malloc and free will be executed rather than the standard ones.

LD_PRELOAD lists shared libraries with functions that override the standard set, just as /etc/ld.so.preload does. These are implemented by the loader /lib/ld-linux.so. If you want to override just a few selected functions, you can do this by creating an overriding object file and setting LD_PRELOAD; the functions in this object file will override just those functions leaving others as they were.
For more information on shared libraries visit
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

To export mylib.so to env:
$ export LD_PRELOAD=/path/mylib.so
$ ./mybin
To disable it:
$ unset LD_PRELOAD

Here is a detailed blog post about preloading:
https://blog.cryptomilk.org/2014/07/21/what-is-preloading/

Using LD_PRELOAD path, you can force the application loader to load provided shared object, over the default provided.
Developers uses this to debug their applications by providing different versions of the shared objects.
We've used it to hack certain applications, by overriding existing functions using prepared shared objects.

When LD_PRELOAD is used, that file will be loaded before any other. Use
$export LD_PRELOAD=/path/lib for lib to be pre-loaded. This can even be used in programs too.

Related

Setting shared libraries prefix when compiling

I'm trying to compile a program, I need to set a prefix path on shared library path, I try using -Wl,-rpath -Wl,-dynamic-linker and what I got from ldd was:
linux-vdso.so.1 => (0x00007fff75336000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f19d55b8000)
/pathtolib/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x000055d3d67e1000)
but what I expecting to get was:
linux-vdso.so.1 => (0x00007fff75336000)
libc.so.6 => /pathtolib/lib/x86_64-linux-gnu/libc.so.6 (0x00007f19d55b8000)
/pathtolib/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x000055d3d67e1000)
I really need to setup this and force program to use non-default path (/pathtolib) for all shared libraries.
this is the command I used to compile:
gcc list/list.c -o bin/list -Wl,-rpath,/pathtolib -Wl,--dynamic-linker,/pathtolib/lib64/ld-linux-x86-64.so.2
what did I do wrong?!! :|
The -rpath option does not specify a prefix for individual directories in the search path; rather, it specifies a colon-delimited list of paths. The dynamic linker searches these directories first, but it continues on to the rest of the search path if it needs to do. Thus, if you want the dynamic linker to resolve libc.so.6 to /pathtolib/lib/x86_64-linux-gnu/libc.so.6, then you must specify not /pathtolib but /pathtolib/lib/x86_64-linux-gnu in your rpath.
I am not aware of a link option or ELF header field that would instruct the dynamic linker to do what you seem to be asking: to modify the standard library search path by prefixing each element. If you want to do something like that, then you probably need to provide your own dynamic linker.
Alternatively, perhaps you want to construct and use a chroot environment instead of of messing with rpaths. That requires considerably more work to set up, but it would have the effect of allowing you to use a whole different set of libraries.

Testprintenv:error while loading shared libraries:libodbc.so.1: cannot open shared object file

I am trying to invoke a C-Program which returns the value for a given keyword from a configuration file
While trying to invoke program it's displaying below error:
**Testprintenv: error while loading shared libraries: libodbc.so.1: cannot open shared object file: No such file or directory**
We have installed EasySoft previously and uninstalled back (Removed all directories).
Below dependencies are showing up on Linux machine
**
-bash-4.1$ ldd Testprintenv
linux-vdso.so.1 => (0x00007fffc0bdb000)
libodbc.so.1 => not found
libodbcinst.so.1 => not found
libc.so.6 => /lib64/libc.so.6 (0x000000397b200000)
/lib64/ld-linux-x86-64.so.2 (0x000000397ae00000)
**
When we try the same program on Solaris machine dependencies are showing up differently and executing without any error:
[Testuser]$ ldd Testprintenv
libsocket.so.1 => /lib/libsocket.so.1
libnsl.so.1 => /lib/libnsl.so.1
libc.so.1 => /lib/libc.so.1
libmp.so.2 => /lib/libmp.so.2
libmd.so.1 => /lib/libmd.so.1
libscf.so.1 => /lib/libscf.so.1
libdoor.so.1 => /lib/libdoor.so.1
libuutil.so.1 => /lib/libuutil.so.1
libgen.so.1 => /lib/libgen.so.1
libm.so.2 => /lib/libm.so.2
/platform/SUNW,SPARC-Enterprise/lib/libc_psr.so.1
Any insight why the dependency (libodbc.so.1) is only showing up on linux and how to resolve?
Thanks in advance,
Is there anyway to check the relationships between c executable and libraries other than ldd?
Any insight why the dependency (libodbc.so.1) is only showing up on
linux and how to resolve?
1) If you want to know why there is a dependency, I suggest to try finding common symbols. Unfortunatelly, you must have the libodbc library installed, because there is no way to find out from the Testprintenv binary which symbols are meant to be linked with this library.
So, do it like this:
# symbols needed by the Testprintenv binary:
nm -uD Testprintenv | tr -s " " | cut -f 3 -d" " > /tmp/symbols_needed
# symbols provided by the libodbc
nm --defined-only -D /lib/PATH_TO_YOUR_LIBRARY/libodbc.so.1 | cut -f 3 -d " " > /tmp/symbols_lib
# intersection of the two sets:
grep -w -F -f /tmp/symbols_needed /tmp/symbols_lib
The last command will list the symbols needed by Testprintenv and provided by libodbc.
2) How to resolve the issue?
first, install the library (libodbc), does it work now?
if not, make sure it is in the standard directories.
if not, add the directory where libodbc resides to the LD_PRELOAD environment variable, like: LD_PRELOAD=/home/ivan/my_lib/
Ok,
First some explanation:
You are trying to use a software that REQUIRES UNIXODBC .
By your OWN result of ldd it says:
**Testprintenv: error while loading shared libraries: libodbc.so.1: cannot open shared object file: No such file or directory**
Now about LDD the man page says:
ldd - print shared library dependencies
So this program you are trying to run DOES NEED the libodbc provided BY UNIXODBC.
You may check rpmfind here.
As Solaris is another platform it may or not use it. (as Solaris has others ways to handle what you are trying to do)
So please check the link and read the install section.
The reason your software is shared linked to UNIXODBC instead of static is
Dynamic Data Binding
This allows the user or the system administrator to easily configure an application to use any ODBC compliant data source. This is perhaps the single biggest advantage of coding an application to the ODBC API and to purchase these applications. Dyamic binding allows the end-user to pick a data source, ie an SQL Server, and use it for all data applications without having to worry about recompiling the application.
By using a non-static dependence easysoft user is able to connect to any database.

What are the effects of linking to a library you do not make function calls to?

I have a make file for a program that links to libdl.so with the following line -ldl. There are no calls to dlopen or any of the related functions. What is the effect of linking to this library in this way even though you do not use any of the functions?
You'll have to read the documentation for your linker. From info ld on my Linux/ELF/GNU Binutils system (emphasis added):
`--as-needed'
`--no-as-needed'
This option affects ELF DT_NEEDED tags for dynamic libraries
mentioned on the command line after the `--as-needed' option.
Normally the linker will add a DT_NEEDED tag for each dynamic
library mentioned on the command line, regardless of whether the
library is actually needed or not. `--as-needed' causes a
DT_NEEDED tag to only be emitted for a library that satisfies an
undefined symbol reference from a regular object file or, if the
library is not found in the DT_NEEDED lists of other libraries
linked up to that point, an undefined symbol reference from
another dynamic library. `--no-as-needed' restores the default
behaviour.
You can check yourself by running ldd on a test program. On a simple test program, I get:
linux-vdso.so.1 => (0x00007fffd8305000)
libc.so.6 => /lib/libc.so.6 (0x00007f646c669000)
/lib/ld-linux-x86-64.so.2 (0x00007f646c9ca000)
However, if I link with -ldl, I get this:
linux-vdso.so.1 => (0x00007fff644f1000)
libdl.so.2 => /lib/libdl.so.2 (0x00007fb9b1375000)
libc.so.6 => /lib/libc.so.6 (0x00007fb9b1014000)
/lib/ld-linux-x86-64.so.2 (0x00007fb9b1579000)
Even though libdl isn't used by my program. However, if I run GCC with -Wl,--as-needed, libdl will not be linked in. According to my tests, this only works if -Wl,--as-needed is listed on the command line before -ldl.
What are the effects? It means that your binary won't run on systems without the shared library, even though you don't use it. It also means that your binary will break if you upgrade the shared library and uninstall the old one. It's not a big deal because binary compatibility is a bear anyway, but I see no reason not to turn on -Wl,--as-needed for projects in general.
I have coded a small application which uses nothing but STL. It has 8275 bytes of size without linking to any specific libraries:
linux-gate.so.1 => (0x00e1e000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0015a000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x0044b000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00741000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00250000)
/lib/ld-linux.so.2 (0x00a75000)
Now, when I compile it and link it with boost_thread, it grows to 8290 bytes:
linux-gate.so.1 => (0x009d9000)
libboost_thread.so.1.40.0 => /usr/lib/libboost_thread.so.1.40.0 (0x00e59000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x003a3000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00bc5000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00f8a000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x00bf0000)
librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x00dd8000)
/lib/ld-linux.so.2 (0x00ba3000)
Note that there is no function call on my code to features of boost_thread. However, boost_thread is added anyway as a dependency of my application (as you can see on the output of ldd).
Linking to a shared library is different than linking a static library. The main differences were explained already by #Dietrich Epp, but there's another important detail. Shared libraries define functions void _init() and void _fini(void) which are called upon loading/unloading a shared library; if you don't define them yourself the linker will add default stubs.
Those will be called also if you link your program against a shared library, but don't reference any symbol from the library (and don't add --as-needed linker flag).
Most linkers will simply omit the unused objects from the final binary, exactly as if you hadn't linked with the library in the first place.

How to force use of static library over shared?

In my SConscript I have the following line:
Program("xtest", Split("main.cpp"), LIBS="mylib fltk Xft Xinerama Xext X11 m")
How do I get scons to use mylib.a instead of mylib.so, while linking dynamically with the other libraries?
EDIT: Looking to use as few platform specific hacks as possible.
Passing the full filepath wrapped in a File node will force static linking. For example:
lib = File('/usr/lib/libfoo.a')
Program('bar', 'main.c', LIBS = [lib])
Will produce the following linker command line
g++ -o bar main.o /usr/lib/libfoo.a
Notice how the "-l" flag is not passed to the linker for this LIBS entry. This effectively forces static linking. The alternative is to modify LINKFLAGS to get what you want with the caveat that you are bypassing the library dependency scanner -- the status of the library will not be checked for rebuilds.
To make this platform independent you append the env['SHLIBSUFFIX'] onto the library you want to use. env['SHLIBSUFFIX'] gives you this environments suffix for shared libraries.
You also have the ['SHLIBPREFIX'], ['LIBPREFIX'], ['LIBSUFFIX'] and ['PROGSUFFIX'], all useful for situations like this.
Edit:
I obviously haven't made myself understood, so I will clarify.
The return value of these lookups are strings to the pre/suffixes that platform uses. In that way you can refer to the file you need on each platform. Note that you cannot use it as a pure string, it has to be embedded as a file node as BennyG suggests. Working with nodes are anyway the best solution as file nodes are much more versatile than a string.
Hope this helps.

Any way to change linking to avoid the LD_PRELOAD on HPUX?

I think I understand why I need LD_PRELOAD set when loading a multithreaded applicatoin that loads a single threaded library that loads libcl.2 but I was wondering if I could use some linker setting to avoid this. Any help appreciated.
Update:
Perl loads
dynamic /usr/lib/libc.2
Perl loads DB2.sl
DB2 Attempts to load
dynamic /usr/lib/libcl.2
Could it be the fact that something with that shared object name is already loaded it then fails.
/usr/lib>pwd
/usr/lib
/usr/lib>ls -lt | grep libcl.2
-r-xr-xr-x 1 bin bin 1261568 Feb 14 2003 libcl.2
lrwxr-xr-x 1 root sys 9 Nov 21 2002 libcl.sl -> ./libcl.2
Now the reason refuses to go looking for something of this same name might be explained by the chattr output:
Both have the disable fields set so they won't look in the environment nor use the alternate name
chatr on perl
perl:
shared executable
shared library dynamic path search:
SHLIB_PATH disabled second
embedded path disabled first Not Defined
shared library list:
dynamic /usr/lib/libnsl.1
dynamic /usr/lib/libnm.sl
dynamic /usr/lib/libdld.2
dynamic /usr/lib/libm.2
dynamic /usr/lib/libsec.2
dynamic /usr/lib/libpthread.1
dynamic /usr/lib/libc.2
chatr on DB2.sl
DB2.sl:
shared library
shared library dynamic path search:
SHLIB_PATH disabled second
embedded path disabled first Not Defined
shared library list:
dynamic /opt/IBM/db2/V8.1/lib/libdb2.sl
dynamic /usr/lib/libcl.2
Could maybe the chatr settings of one of the libraries be adjusted?
Update: why not just make them use the same name for the library.
Depending on your compiler/linker (thinking of the HPUX machines I logged onto more than a decade ago makes me shudder), --rpath might help: from what I understand, in your case the rtld is looking in the wrong place first, so that's why you want to preload some other version of the lib, right? In that case, rpath will embed an additional search location into the compiled binary, which you can use to point it to the directory where your preferred version is coming from.
Hope this helps. -V
I wrote an article about shared libraries on HP-UX and tried to make it clear and comprehensive. I found myself having to debug why programs couldn't find their libraries and so I documented it.
The three main locations that will affect the library search are 1) /etc/SHLIBPATH; 2) environment variables; and 3) the embedded library search path.
Unfortunately, this is a drastic oversimplification: the best reference I have to offer is that article that brings everything together (in my opinion, any way).
There are not linker flags to avoid this.

Resources