I have been stuck in a problem for several days when using dlopen/dlsym to deal with the shared object. I desperately need your help!
There are three headers/source files: Animal.h, Animal.cpp and test.cpp, and two products: libanimal.so and a.out.
Here is the source code:
Animal.h:
// Animal.h #ifndef STDLIB_ANIMAL_H #define STDLIB_ANIMAL_H #include <string> class Animal { public: Animal(); std::string shout(); }; extern "C" Animal* createAnimal(); #endif //STDLIB_ANIMAL_H
Animal.cpp
// Animal.cpp #include "Animal.h" Animal::Animal() = default; std::string Animal::shout() { return "WOW"; } Animal* createAnimal() { return new Animal(); }
and the last one test.cpp which contained the main entry of the application:
// test.cpp #include <cstdio> #include <cstdlib> #include <string> #include <dlfcn.h> #include <iostream> #include "Animal.h" int main(int argc, char** argv) { void *handle; // Open shared library handle = dlopen("./libanimal.so", RTLD_LAZY); if (!handle) { /* fail to load the library */ fprintf(stderr, "Handle Error: %sn", dlerror()); return EXIT_FAILURE; } auto spawnAnimal = reinterpret_cast<Animal* (*)()>(dlsym(handle, "createAnimal")); if (!spawnAnimal) { /* no such symbol */ fprintf(stderr, "No Such Symbol Error: %sn", dlerror()); dlclose(handle); return EXIT_FAILURE; } auto animal = spawnAnimal(); std::cout << "call animal shout, the address of animal : " << animal <<std::endl; std::cout << animal->shout() << std::endl; std::cout << "after calling" << std::endl; dlclose(handle); return EXIT_SUCCESS; }
First, I built libanimal.so shared library by the following command:
$ g++ -shared -fPIC -Wall -o libanimal.so Animal.cpp -std=c++0x
Then I built the executable, a.out:
$ g++ -Wall test.cpp -ldl -std=c++0x -Wl,--unresolved-symbols=ignore-in-object-files # --unresolved-symbols=ignore-all: tell linker to stop complaining about missing symbols
Both the above commands ran well without any error, but when I execute a.out, errors came out:
$ ./a.out call animal shout, the address of animal : 0x7fffe97a4520 Segmentation fault (core dumped)
I have searched lots of blogs/documentations, but all of them just post a really simple example:
The function they export always return like a std::string or char or int which is built-in type, not something like a object of a user-defined class, just like the showcase above (the createAnimal function).
So what’s wrong with this? Could you please help me figuring out ?
Thank you !
BTW, my environment is:
$ g++ --version g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Advertisement
Answer
Ok, my suspicion from the comment has confirmed itself. The problem is with the early binding on animal->shout()
which resolves at compile time to a call to _ZN6Animal5shoutB5cxx11Ev
and this symbol is nowhere to be found.
If I change it to virtual (late binding, resolved at runtime through a vtable):
// Animal.h #ifndef STDLIB_ANIMAL_H #define STDLIB_ANIMAL_H #include <string> class Animal { public: Animal(); virtual std::string shout(); virtual ~Animal() {} // always put a virtual destructor if you have any virtual methods }; extern "C" Animal* createAnimal(); #endif //STDLIB_ANIMAL_H
Now it runs.