Why LD_PRELOAD doesn't work for one of loaded shared libraries?
It seeems that http.so is loaded with the RTLD_DEEPBIND flag and that is why LD_PRELOAD is ignored for one of shared libraries.
This is from http://linux.die.net/man/3/dlopen:
RTLD_DEEPBIND (since glibc 2.3.4)
Place the lookup scope of the symbols in this library ahead of the global scope. This means that a self-contained library will use its
own symbols in preference to global symbols with the same name
contained in libraries that have already been loaded. This flag is not
specified in POSIX.1-2001.
I wrote a test shared library:
#include <dlfcn.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void initialize_my_dlopen(void) __attribute__((constructor));
void* (*real_dlopen)(const char *, int flag);
static int unset_RTLD_DEEPBIND=0;
static int _initialized = 0;
static void initialize_my_dlopen(void)
{
if (_initialized)
return;
real_dlopen = (void *(*)(const char *,int))dlsym(RTLD_NEXT, "dlopen");
unset_RTLD_DEEPBIND = atoi(getenv("UNSET_RTLD_DEEPBIND") ? getenv("UNSET_RTLD_DEEPBIND") : "0");
printf("unset_RTLD_DEEPBIND: %d\n", unset_RTLD_DEEPBIND);
_initialized = 1;
}
extern "C" {
void *dlopen(const char *filename, int flag)
{
int new_flag = unset_RTLD_DEEPBIND == 0 ? flag : flag & (~RTLD_DEEPBIND);
return (*real_dlopen)(filename, new_flag);
}
}
And built it:
gcc -shared -fPIC -g -m64 my_dlopen.cpp -o libmy_dlopen.so -ldl
When I set UNSET_RTLD_DEEPBIND to 0 and run httpd
the program coredumps.
export UNSET_RTLD_DEEPBIND=0
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config
When I set UNSET_RTLD_DEEPBIND to 1 and run httpd
everything is OK.
export UNSET_RTLD_DEEPBIND=1
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config
And this is the output of LD_DEBUG=all for the UNSET_RTLD_DEEPBIND to 1:
10678: symbol=free; lookup in file=/apache2/bin/httpd [0]
10678: symbol=free; lookup in file=/apache2/libmy_dlopen.so [0]
10678: symbol=free; lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
10678: binding file /apache2/ext/http.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free'
Not able to use function from my dynamic library loaded via LD_PRELOAD
sscanf()
may be a macro referencing an internal function. Have a look at <stdio.h>. For example, on my system, I have:
extern int __isoc99_sscanf (const char *__restrict __s,
const char *__restrict __format, ...) __THROW;
# define fscanf __isoc99_fscanf
# define scanf __isoc99_scanf
# define sscanf __isoc99_sscanf
Hence, sscanf()
is actually a macro referencing __isoc99_sscanf()
. So, if you redefine the latter, you get what you expect.
#include <stdarg.h>
#include <stdio.h>
//__attribute__((force_align_arg_pointer)) int sscanf(const char *str, const char *format, ...)
int __isoc99_sscanf(const char *str, const char *format, ...)
{
int ret;
va_list ap;
va_start(ap, format);
printf("test\n");
ret = vsscanf(str, format, ap);
va_end(ap);
return ret;
}
After rebuild, you get:
$ gcc -fPIC -shared preload.c -o preload.so -ldl -D_GNU_SOURCE=1
$ LD_PRELOAD=`pwd`/preload.so ./foo
test
42
Error when trying to link to a shared library I created using LD_PRELOAD
I do not know how to add compiler flag, but you can make it works as follows.
Compile test as usual:
g++ -Wall -g test.cpp -o test -std=c++11
Invoke it like this:
LD_PRELOAD=/home/nullmalloc/nullmalloc.so ./test
What is the LD_PRELOAD trick?
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
Change library load order at run time (like LD_PRELOAD but during execution)
AFAIK, that is not possible. The general rule is that if the same symbol appears in two libraries, ld.so will favor the library that was loaded first. LD_PRELOAD works by making sure the specified libraries are loaded before any implicitly loaded libraries.
So once execution has started, all implicitly loaded libraries will have been loaded and therefore it's too late to load your library before them.
Why does `LD_DEBUG=libs` fail to display a library that loaded in an application?
It's because the qtcreator process does not load the libqbscore.so. The qbs child process loads it.
Because Qt Creator and Qbs are open source projects, their interactions can be analyzed by analyzing the source codes.
why is library loaded via LD_PRELOAD operating before initialization?
Obviously, fopen
is called before initialization of comm.so
. It is interesting to place a breakpoint in fopen()
in order to understand (check this link in order to get debug symbols of various packages). I get this backtrace:
(gdb) bt
#0 fopen (filename=0x7ffff79cd2e7 "/proc/filesystems", mode=0x7ffff79cd159 "r") at comm.c:28
#1 0x00007ffff79bdb0e in selinuxfs_exists_internal () at init.c:64
#2 0x00007ffff79b5d98 in init_selinuxmnt () at init.c:99
#3 init_lib () at init.c:154
#4 0x00007ffff7de88aa in call_init (l=<optimized out>, argc=argc@entry=1, argv=argv@entry=0x7fffffffdf58, env=env@entry=0x7fffffffdf68) at dl-init.c:72
#5 0x00007ffff7de89bb in call_init (env=0x7fffffffdf68, argv=0x7fffffffdf58, argc=1, l=<optimized out>) at dl-init.c:30
#6 _dl_init (main_map=0x7ffff7ffe170, argc=1, argv=0x7fffffffdf58, env=0x7fffffffdf68) at dl-init.c:120
#7 0x00007ffff7dd9c5a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#8 0x0000000000000001 in ?? ()
#9 0x00007fffffffe337 in ?? ()
#10 0x0000000000000000 in ?? ()
It is obvious, comm.so
depends on other libraries (libdl.so
that requires libselinux.so
). And comm.so
is not the only library that declare an init function. libdl.so
and libselinux.so
also declare ones.
So, comm.so
is the first library to be loaded (because it is declared with LD_PRELOAD
) but, comm.so
depends on libdl.so
(because of -ldl
during compilation) and libdl.so
depends on libselinux.so
. So, in order to load comm.so
, init functions from libdl.so
and libselinux.so
are called before. And finally, init function from libselinux.so
call fopen()
Personally, I usually resolve dynamic symbols during first call to the symbol. Like this:
FILE *fopen(const char *filename, const char *mode) {
static FILE *(*real_fopen)(const char *filename, const char *mode) = NULL;
if (!real_fopen)
real_fopen = dlsym(RTLD_NEXT, "fopen");
return real_fopen(filename, mode);
}
Related Topics
Why Do My Sfinae Expressions No Longer Work with Gcc 8.2
Why Does My Program Run Way Faster When I Enable Profiling
Is There a Default Hash Function for an Unordered_Set of a Custom Class
What Is Double Evaluation and Why Should It Be Avoided
Move the String Out of a Std::Ostringstream
Volatile Struct = Struct Not Possible, Why
Non-Const Reference May Only Be Bound to an Lvalue
Ubuntu System Monitor and Valgrind to Discover Memory Leaks in C++ Applications
Gcc Does Not Honor 'Pragma Gcc Diagnostic' to Silence Warnings
Could Not Load Spatialite Extension in Qsqlite ( Qt 5.9)
Use Static_Assert to Check Types Passed to MACro
Specializing Single Method in a Big Template Class
How to Calculate Offset of a Class Member at Compile Time
Extract Text from PDF Document Based on Position C++
Cost of Using Std::Map with Std::String Keys VS Int Keys
C++: How to Check Type of Files Without Extension
What Is The Linux Equivalent Of: Multibytetowidechar & Widechartomultibyte