I'm trying to create a shared library containing a base class so that it could be derived:
base.h
class Base
{
public:
virtual ~Base () {}
virtual void Function ();
};
base.cpp
#include <stdio.h>
#include "base.h"
void Base::Function ()
{
printf ("base function\n");
}
mybase.so
g++ -fpic -g -shared base.cpp -o libbase.so
main.cpp
#include "base.h"
class Derived : public Base
{
};
int main (int argc, char** argv)
{
Derived* d = new Derived ();
d->Function ();
delete d;
return 1;
}
I also want to avoid linking the executable with the shared library, so I create it by ignoring unresolved symbols:
test
g++ -fpic -rdynamic -Wl,--unresolved-symbols=ignore-in-object-files -g main.cpp -o test
Finally I use LD_PRELOAD environment variable for preloading the shared library before execution
LD_PRELOAD=./libbase.so ./test
Segmentation fault (core dumped)
I've noticed the problem is that virtual table for Derived object is undefined for "Function":
(gdb) info vtbl d
vtable for 'Derived' @ 0x601030 (subobject @ 0x602010):
[0]: 0x400c7e <Derived::~Derived()>
[1]: 0x400cc0 <Derived::~Derived()>
[2]: 0x0
My guess is that when executable gets loaded, the dynamic linker cannot resolve the vtable entries since the shared library has not been loaded yet.
So my question is: Is there a way of making this work? Maybe forcing somehow to load the shared library before the executable...
BTW: By making "Function" non virtual everything works OK, since no vtable is needed for Derived class.
UPDATE 1: Using an object instead a pointer makes main to work:
int main (int argc, char** argv)
{
Derived d;
d.Function (); // prints "base function"
return 1;
}
UPDATE 2: Doing the same as in main but in a second shared library also works:
mylib.cpp
#include "base.h"
class DerivedLib : public Base
{
};
extern "C" void do_function()
{
DerivedLib* d = new DerivedLib();
d->Function();
delete d;
}
mylib.so
g++ -fPIC -g -shared lib.cpp -o libmylib.so
main.cpp
#include "base.h"
#include <dlfcn.h>
class Derived : public Base
{
};
int main (int argc, char** argv)
{
void* handle = dlopen("libmylib.so", RTLD_LAZY);
void (*do_function)();
do_function = (void (*)())dlsym(handle, "do_function");
do_function(); // prints "base function"
Derived* d = new Derived();
d->Function (); // <- crashes
delete d;
return 1;
}
So definitely problem arises when a new instance pointer is created inside the executable