Limitations when dynamically loading a shared object from another shared object?

I dynamically load (whith dlopen() ) a shared object (named libprofile1.so ) from main .

In libprofile1.so I defined the factory function CreateProfile and class Profile . The CreateProfile function creates an instance of the Profile class and returns a pointer to it. The Profile class has a pMethod method.

Basically, after loading libprofile1.so , I call the CreateProfile method, which returns a pointer to an object of the Profile class (name it p ).
Subsequently, I call the pMethod method against the p object ( p->pMethod ). In this method, I dynamically load another shared object ( libdatasources.so ).

In this generic object, I have a factory function CreateDataSource and class DataSource .
The CreateDataSource function creates an instance of the DataSource class and returns a pointer to it. DataSource class has a dsMethod method.

As you can see, the structures of both common objects are similar.

From pMethod after loading libdatasources.so I call the CreateDataSource method, which returns me a pointer to an instance of the DataSource class, calls it ds . Then I call the dsMethod of the ds object
( ds->dsMethod ).


Now the problem is as follows.

When I try to call the dsMethod of the ds object, the generic object that I load first ( libprofile1.so ) does not load. In fact, dlopen() returns NULL . When I read dlerror after dlopen , I get:

./libprofile1.so: undefined symbol: _ZN18DataSource13dsMethod

So, if I have a call to ds->Method , then the first shared object does not load!
If I comment on the call to ds->dsMethod from the source, then my libprofile1.so and libdatasources.so load without problems.
I do not see the connection between the method call from the second SO, loading SO first ???

Maybe I don’t know, but are there any restrictions when dynamically loading a shared object from a shared object that was also dynamically loaded?

Btw, dlopen used with RTLD_NOW|RTLD_GLOBAL . I tried with RTLD_LAZY , but still the same problem.

UPDATE:

Libraries are built into Eclipse. The options for the g ++ compiler and linker are the same for both libraries.
Here is the g ++ compiler:

 -O0 -g3 -Wall -c -fmessage-length=0 

and g ++ linker:

 -shared 

inserted with Project Properties -> Settings -> Tool Settings

Thanks in advance.

+6
c ++ linux shared-libraries
source share
2 answers

If you dynamically load a DLL, you must ensure that it does not have unresolved characters.

The easiest way to do this is to link it to other DLLs that it needs to load automatically, and not you have to load and resolve all the dependencies manually.

Therefore, if libprofile1 always uses libdatasources , make sure they are related to each other.

If you must do this manually, change the loading order of the libraries. That way, when you load libprofile1 , the functions it needs are already loaded.

+3
source share

As Martin York noted, this is the way he works on Linux. When linking to a library, you must also reference all dependencies. On Windows, different DLLs take care of their dependencies themselves. When loading a library dynamically that has another library as a dependency, you must first load the library with the RTLD_GLOBAL flag. This is pretty awkard, imho, since you cannot know what dependencies other common objects require, or the dependencies may change with a newer version that would otherwise be compatible with binary ones. From what I know (and from reading g ++ and ld manpages), it is not possible to create behavior similar to Windows DLLs. Here is a small test file:

two.cpp:

 #include <iostream> extern "C" { void bar() { std::cout << "bar()\n"; } } 

one.cpp:

 #include <iostream> extern "C" { void bar(); void foo() { std::cout << "foo()\n"; bar (); } } 

test.cpp:

 #include <dlfcn.h> #include <iostream> int main (int argc, char *argv[]) { using namespace std; // void *libtwo = dlopen("./libtwo.so", RTLD_NOW | RTLD_GLOBAL); void *libone = dlopen("./libone.so", RTLD_NOW); if (!libone) { cout << "dlopen(libone.so) failed: " << dlerror() << "\n"; return 1; } typedef void (*foo_t)(); foo_t foo = reinterpret_cast<foo_t>(dlsym(libone, "foo")); if (!foo) { cout << "dlsym(libone.so, foo) failed\n"; return 2; } } 

one.cpp is compiled in libone.so and two.cpp in libtwo.so , test.cpp is compiled into the test binary. This will not succeed and will be successful only when the commented line is uncommented.

+4
source share

All Articles