Dynamically loading Linux shared libraries? - linux

I want to create a shared library which can be loaded in two different ways into targets:
LD_PRELOAD
Dynamic loading via dlsym
My shared library looks like this:
#include "stdio.h"
void __attribute__ ((constructor)) my_load(void);
void my_load(void) {
printf("asdf");
}
void someFunc(void) {
printf("someFunc called");
}
I am compiling it like so:
all:
gcc -fPIC -g -c -Wall MyLib.c
gcc -shared -W1,-soname,MyLib.so.1 -o MyLib.so.1.0.1 -lc
I do not wish to install it with ldconfig, etc. The target process looks like this:
#include <stdio.h>
#include <dlfcn.h>
void func1() {
printf("%d\n", 1);
}
void func2() {
printf("%d\n", 2);
}
void func3() {
printf("%d\n", 3);
}
int main() {
void* lib_handle = dlopen("/home/mike/Desktop/TargetProcess/MyLib.so.1.0.1",
RTLD_NOW|RTLD_GLOBAL);
if(lib_handle == NULL) {
printf("Failed loading lib\n");
} else {
printf("Loaded lib successfully\n");
void (*some_func)() = dlsym(lib_handle, "someFunc");
printf("%p\n", some_func);
dlclose(lib_handle);
}
func1();
func2();
func3();
return 0;
}
The target is compiled as so:
all:
gcc TestProg.c -ldl -o TestProg
My questions are:
With the dynamic loading with dlopen as above, why does my_load not appear to be called?
With the same method, why does dlsym always return nil even though dlopen returns non-null? Similarly, nm doesn't list either my_load or someFunc as symbols of the .so.
Is it possible to use LD_PRELOAD to load the library? I tried copying the .so into the same directory as the target then invoking LD_PRELOAD="./MyLib.so.1.0.1" ./TestProg but again my_load seems not to be being called.

Your object files was no linked into your library:
gcc -shared -W1,-soname,MyLib.so.1 -o MyLib.so.1.0.1 -lc
Change it to include your object file MyLib.o:
gcc MyLib.o -shared -W1,-soname,MyLib.so.1 -o MyLib.so.1.0.1 -lc
UPDATE: just tryed your command locally (without any MyLib.c or MyLib.o):
$ gcc -shared -W1,-soname,MyLib.so.1 -o MyLib.so.1.0.1 -lc && echo ok
ok
$ nm MyLib.so.1.0.1
xxxxxxxx a _DYNAMIC
xxxxxxxx a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
xxxxxxxx A __bss_start
w __cxa_finalize##xxxxxxxxxxx
xxxxxxxx d __dso_handle
w __gmon_start__
xxxxxxxx t __i686.get_pc_thunk.bx
xxxxxxxx A _edata
xxxxxxxx A _end
xxxxxxxx T _fini
xxxxxxxx T _init
It is an empty dynamic library.

Related

Libicu, undefined reference while compiling

I'm trying to use the lib icu in my shared library.
So i generate my .so who use libicu functions, this parts works well.
Then i try to compile my main program, using the shared library that i created before. But i get the following error:
release//libstring.so: undefined reference to `u_errorName_53'
release//libstring.so: undefined reference to `ucnv_toUnicode_53'
release//libstring.so: undefined reference to `ucnv_close_53'
release//libstring.so: undefined reference to `ucnv_fromUChars_53'
release//libstring.so: undefined reference to `udat_open_53'
release//libstring.so: undefined reference to `udat_parse_53'
release//libstring.so: undefined reference to `udat_format_53'
release//libstring.so: undefined reference to `ucnv_toUChars_53'
release//libstring.so: undefined reference to `ucnv_open_53'
release//libstring.so: undefined reference to `udat_close_53'
I have installed the libicu with this help.
I compile my shared library with -licuuc, as well as my main program compile only with -l:libstring.so and -licuuc.
When i do ldd libstring.so, i don't have the .so of the libicu on the list of dependencies.
The problem probably come from this.
Thx
EDIT: I have create a little test:
icu.h:
#pragma once
#include <iostream>
#include <string>
#include <unicode/ucnv.h>
class c_icu
{
private:
void * p_priv;
public:
c_icu();
void open(const wchar_t *name);
void to_local(std::wstring &, std::wstring &);
void from_local(std::wstring &, std::wstring &);
void close(void);
~c_icu();
};
icu.cpp:
#include "icu.h"
c_icu::c_icu()
{
p_priv = NULL;
}
c_icu::~c_icu()
{
if (p_priv)
close();
}
void c_icu::open(const wchar_t *name)
{
UErrorCode status = U_ZERO_ERROR;
char conv_name[256];
if (wcstombs(conv_name, name, 256) == (size_t)-1)
{
std::cout << "ERROR: wcstombs failed" << std::endl;
exit(0);
}
if ((p_priv = (UConverter *)ucnv_open(conv_name, &status)) == NULL)
{
std::cout << "ERROR: ucnv_open failed" << std::endl;
exit(0);
}
}
void c_icu::to_local(std::wstring &src, std::wstring &dst)
{
UErrorCode status = U_ZERO_ERROR;
int32_t len;
len = ucnv_toUChars((UConverter *)p_priv, (UChar *)NULL, 0, (const char *)src.c_str(), src.size(), &status);
if (status == U_BUFFER_OVERFLOW_ERROR)
{
status = U_ZERO_ERROR;
dst.resize(len);
len = ucnv_toUChars((UConverter *)p_priv, (UChar *)dst.c_str(), dst.size(), (const char *)src.c_str(), src.size(), &status);
if (U_FAILURE(status))
{
std::cout << "ERROR: to_local failed" << std::endl;
exit(0);
}
}
}
void c_icu::from_local(std::wstring &src, std::wstring &dst)
{
UErrorCode status = U_ZERO_ERROR;
int32_t len;
len = ucnv_fromUChars((UConverter *)p_priv, (char *)NULL, 0, (const UChar *)src.c_str(), src.size(), &status);
if (status == U_BUFFER_OVERFLOW_ERROR)
{
status = U_ZERO_ERROR;
dst.reserve(len);
len = ucnv_fromUChars((UConverter *)p_priv, (char *)dst.c_str(), dst.size(), (const UChar *)src.c_str(), -1, &status);
}
}
void c_icu::close(void)
{
ucnv_close((UConverter *)p_priv);
p_priv = NULL;
}
test.cpp:
#include "icu.h"
int main(void)
{
c_icu converter;
std::wstring src = L"";
std::wstring dst;
const wchar_t add[11] = L"Just a test";
const wchar_t *unicode = L"koi8-r";
for (unsigned int i = 0; i < 1000; i++)
src.append(add, 11);
converter.open(unicode);
converter.from_local(src, dst);
converter.close();
}
Makefile:
NAME= test
LIB_NAME= libicutest.so
FLAGS= -W -Wall -Wextra
all: lib $(NAME)
$(NAME):
#echo "Main programm compiling ..."
g++ -c test.cpp -o test.o $(FLAGS)
g++ -o $(NAME) test.o -Wl,-rpath,'$$ORIGIN/' -licui18n -L. -licutest
#echo "Main programm compiled"
lib:
#echo "Lib Compiling ..."
g++ -std=gnu++11 -c -fPIC icu.cpp -o icu.o $(FLAGS)
g++ -shared -Wl,-soname,$(LIB_NAME) -o $(LIB_NAME) icu.o -licui18n
#echo "Lib Compiled"
Note: even with -licuuc instead of -licui18n i got the same error.
Output:
$> make
Lib Compiling ...
g++ -std=gnu++11 -c -fPIC icu.cpp -o icu.o -W -Wall -Wextra
g++ -shared -Wl,-soname,libicutest.so -o libicutest.so icu.o -licui18n
Lib Compiled
Main programm compiling ...
g++ -c test.cpp -o test.o -W -Wall -Wextra
g++ -o test test.o -Wl,-rpath,'$ORIGIN/' -licui18n -L. -licutest
./libicutest.so: undefined reference to `ucnv_close_53'
./libicutest.so: undefined reference to `ucnv_fromUChars_53'
./libicutest.so: undefined reference to `ucnv_toUChars_53'
./libicutest.so: undefined reference to `ucnv_open_53'
collect2: error: ld returned 1 exit status
make: *** [test] Error 1
If i do ldd on my shared library:
$> ldd libicutest.so
linux-vdso.so.1 => (0x00007ffd5eb7f000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f092b5e6000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f092b221000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f092af1a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f092bb00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f092ad04000)
EDIT2:
Ok, seems that the problem is easier to solve than expected. My program need function in icu_53, but i got icu_48 installed on my computer dunno why.
$> locate libicu
/usr/lib/x86_64-linux-gnu/libicudata.so.48
/usr/lib/x86_64-linux-gnu/libicudata.so.48.1.1
/usr/lib/x86_64-linux-gnu/libicui18n.so.48
/usr/lib/x86_64-linux-gnu/libicui18n.so.48.1.1
/usr/lib/x86_64-linux-gnu/libicuio.so.48
/usr/lib/x86_64-linux-gnu/libicuio.so.48.1.1
/usr/lib/x86_64-linux-gnu/libicule.so.48
/usr/lib/x86_64-linux-gnu/libicule.so.48.1.1
/usr/lib/x86_64-linux-gnu/libiculx.so.48
/usr/lib/x86_64-linux-gnu/libiculx.so.48.1.1
/usr/lib/x86_64-linux-gnu/libicutest.so.48
/usr/lib/x86_64-linux-gnu/libicutest.so.48.1.1
/usr/lib/x86_64-linux-gnu/libicutu.so.48
/usr/lib/x86_64-linux-gnu/libicutu.so.48.1.1
/usr/lib/x86_64-linux-gnu/libicuuc.so.48
/usr/lib/x86_64-linux-gnu/libicuuc.so.48.1.1
Does anyone know how to upgrade the version from icu_48 to icu_53 at least ?
Seems 'udat_parse_53' is located inside libicui18n.so.53 library. Try to compile your project with '-licui18n' option.

Issue with dlopen and weak symbols

I have the following sequence
executable (main) ---- (dlopen)---> libapp.so ---(dynamically linked)--> libfoo.so
libfoo.so in turn dynamically links to libfoo_strong.so. libfoo.so invokes a function from
libfoo_strong.so, but also has a weak definition (within foo.c which is compiled into libfoo.so).
Now, libapp.so invokes a function from libfoo.so (say invoke_foo_func_ptr() and this function >invokes a function pointer which stores the symbol that is defined as weak. My expectation is that >invokes_foo_func_ptr invokes the strong symbol, but it always goes to the weak symbol. Pls see the >code below for details.
PS: Dont ask me to explain the reason particular sequence of execution, but I am open to >workarounds.
foo_strong.c --> gcc -g -fPIC -shared -rdynamic foo_strong.o -o libfoo_strong.so
foo.c: --> gcc -g -fPIC -shared -rdynamic -L/users/ardesiga/cprogs/ld_r foo.o -o libfoo.so
app.c: --> gcc -g -fPIC -shared -rdynamic -L/users/ardesiga/cprogs/ld_r -lfoo -lfoo_strong app.o -o > libapp.so
/* foo_strong.c */
int
foo_weak_func (char *msg)
{
printf("[%s:%s] Reached strong, with msg: %s\n", __FILE__, __FUNCTION__, msg);
}
/* foo.c */
#include <stdio.h>
#include <stdlib.h>
#include "foo_ext.h"
#include "foo_weak.h"
int __attribute__ ((weak)) foo_weak_func (char *msg)
{
printf("[%s:%s], Reached weak, with msg: %s\n", __FILE__, __FUNCTION__, msg);
}
typedef int (*func_ptr_t) (char *msg);
func_ptr_t foo_func_ptr = foo_weak_func;
void
invoke_foo_func_ptr (char *msg)
{
printf("Inside %s\n", __FUNCTION__);
if (foo_func_ptr) {
(*foo_func_ptr)(msg);
} else {
printf("foo_func_ptr is NULL\n");
}
}
/* app.c */
#include "foo.h"
int
app_init_func (char *msg)
{
printf("Inside %s:%s\n", __FILE__, __FUNCTION__);
invoke_foo_func_ptr(msg);
}
/* main.c */
int main (int argc, char *argv[])
{
void *dl_handle;
char *lib_name;
app_init_func_t app_init_func;
if (!(argc > 1)) {
printf("Library is not supplied, loading libapp.so\n");
lib_name = strdup("libapp.so");
} else {
lib_name = strdup(argv[2]);
}
printf("Loading library: %s\n", lib_name);
dl_handle = dlopen(lib_name, RTLD_LAZY);
if (!dl_handle) {
printf("Failed to dlopen on %s, error: %s\n", lib_name, dlerror());
exit(1);
}
app_init_func = dlsym(dl_handle, "app_init_func");
if (app_init_func) {
(*app_init_func)("Called via dlsym");
} else {
printf("dlsym did not file app_init_func");
}
return (0);
}
My expectation is that invokes_foo_func_ptr invokes the strong symbol, but it always goes to the weak symbol.
Your expectation is incorrect and everything is working as designed.
Weak symbols lose to strong symbols when you link a single ELF binary. If you were to link a normal (strong) function foo and a weak foo into libfoo.so, the the strong definition would have won.
When you have multiple ELF images, some with strong foo, and some with weak foo, the first ELF image to define foo (regardless of whether weak or strong) wins. The loader will simply not look for any additional ELF images in its search scope once it finds the first image that does provide a definition for foo.
Dont ask me to explain the reason particular sequence of execution
That is quite an obnoxious thing to say.
I have a guess as to what your reason may be, and a solution for it, but you'll have to provide your reason first.

thread boost cannot resolve overloaded function

I want to create a new thread which will run a function, but When I compile the terminal display the following error message :
g++ -o main.o -c main.cpp -O0 -g -Wall -fmessage-length=0 -D__STDC_CONSTANT_MACROS -std=gnu++0x -lboost_filesystem -lboost_log_setup -lboost_log -lboost_chrono -lboost_thread -lz -lpthread -ldl -lm
main.cpp: In function ‘int main(int, char**)’:
main.cpp:35:13: error: statement cannot resolve address of overloaded function
make: *** [main.o] Error 1
I can't give you my whole code because stackoverflow refuse to post the message if I include code inside.
Here is a sample :
void foo();
boost::thread t(foo);
Any help would be appreciate. Thanks
Unless it is a static method, you need to use bind() (you need bind() whenever you either launch non-static methods).
Example:
class Worker {
int returnValue_;
public:
inline void Run() {
//...
boost::this_thread::sleep(boost::posix_time::seconds(2));
returnValue_ = 3;
}
inline int getValue() const {
return returnValue_;
}
};
Worker worker;
boost::thread th (boost::bind(&Worker::Run, &worker));

LD_PRELOAD loaded event

I writed my LD_PRELOAD module and i want to add some initialization code before my overrided functions work. Maybe LD_PRELOAD have any loaded event or something like this?
Thanks!
I'm not sure about a "loaded" event, however if you're using gcc, you may find the constructor attribute useful. Take for example:
testlib.c:
#include
void testing(void) __attribute__((constructor));
void testing(void)
{
printf("It worked!\n");
}
hworld.c:
#include <stdio.h>
int main(void)
{
printf("Hello world!\n");
return 0;
}
$ gcc -o hworld hworld.c
$ gcc -shared -fPIC -o testlib.so testlib.c
$ export LD_PRELOAD=./testlib.so
$ ./hworld
It worked!
Hello world!
The constructor attribute means that the function should be executed before main(). Alternatively, if you're using C++, you could create a static global instance of a class whose constructor does the initialization, which would achieve the same effect as using constructor.

How can dlsym successfully import function from stripped binary library?

It's weird that dlsym can import functions from stripped binaries.
Can anyone tell me why/how?
=== FILE: a.c ===
int a1() { return 1; }
int a2() { return 2; }
=== end of a.c ===
=== FILE: b.c ===
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
typedef int (*fint)();
fint dlsym_fint(void *handle, char *name)
{
fint x = (fint)dlsym(handle, name);
char *err = NULL;
if ((err = dlerror()) != NULL) {
printf("dlsym: %s\n", err);
exit(1);
}
return x;
}
int main()
{
void *dl = dlopen("a.so", RTLD_NOW);
fint a = NULL;
a = dlsym_fint(dl, "a1");
printf("%p: %d\n", a, a());
a = dlsym_fint(dl, "a2");
printf("%p: %d\n", a, a());
return 0;
}
=== end of b.c ===
$ gcc -shared -fPIC -o a.so a.c
$ nm a.so
...
00000000000004ec T a1
00000000000004f7 T a2
...
$ strip a.so
$ nm a.so
nm: a.so: no symbols
$ gcc -o b b.c -ldl
$ ./b
0x2aaaaaac74ec: 1
0x2aaaaaac74f7: 2
Try readelf -s a.so. The dynamic symbols are still there after that strip.
(Or just switch to nm -D a.so.)
strip removes debugging symbol tables, not the dynamic symbol tables used by the dynamic linker. To remove those symbols as well, use -fvisibility=hidden, and the symbol visibility function/variable attributes to select which functions you want to expose.

Resources