I have a C++ program which I need to open a shared object (.so) and load a C++ class from it. I have seen this done on the internet and I have loaded many things using dlsym() in both C and C++, so I know how everything works. However, there is a slight difference I need to make. The class I am loading with dlsym() must be a child class of another class which is defined in a header used by both the shared object and the main program. The idea is to load a bunch of different custom versions of this class at runtime. Linking with the object at compile-time is not an option. Here is what I have done (heavily abbreviated, but all the important parts are there):
BaseClass.h:
class BaseClass {
public:
virtual ~BaseClass();
virtual int function(int, int);
};
ChildClass.h:
extern "C" BaseClass* makechild();
ChildClass.cpp:
class ChildClass : public BaseClass {
public:
int function(int a, int b) override { return a + b; }
};
BaseClass* makechild() {
return new ChildClass();
}
main.cpp:
std::function<BaseClass*(void)> make;
// note that in the actual program I throw a std::runtime_error with
// dlerror() as its message when this goes wrong, and I don't handle it
make = reinterpret_cast<BaseClass*(*)(void)>(dlsym(handle, "makechild"));
BaseClass* myclass = make();
I then compile the ChildClass.cpp as ChildClass.so (using -shared -fpic) and I compile main.cpp with -ldl and some other warning-related flags and such. Using g++ and clang++ I get two different errors at runtime:
- After compiling with clang++:
undefined symbol: _ZN9BaseClassD2Ev - After compiling with g++:
undefined symbol: _ZTI9BaseClass
After checking the .so file with objdump and readelf, I confirm that this symbol is indeed undefined:
...
0000000000000000 *UND* 0000000000000000 _ZN9BaseClassD2Ev
...
0000000000000000 *UND* 0000000000000000 _ZTI9BaseClass
...
I am not sure what these symbols mean exactly. After a little bit of reading of the ABI docs, it seems the first might be a dtor or something, and the second is probably the ctor or the class itself, something like that. In any case, I am not explicitly trying to load these, but I am not sure why they are undefined. Is it possible to do this polymorphism/inheritance setup with dlsym() and C++?
Edit: Thanks to a comment, I have used the C++filt program to find out that the destructor was missing (I just added virtual ~BaseClass() = default; to fix that). Now the one thing missing is the _ZTI one, which is the typeinfo for the class.
echo _ZTI9BaseClass | c++filtto demangle that nameBaseClassdestructor._ZTI9BaseClass, which appears to be the type info for the base class.BaseClass::functionimplemented?