Я пытаюсь создать разделяемую библиотеку, содержащую базовый класс, чтобы он мог быть получен:
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;
}
Я также хочу избежать связывания исполняемого файла с общей библиотекой, поэтому я создаю его, игнорируя неразрешенные символы:
test
g++ -fpic -rdynamic -Wl,--unresolved-symbols=ignore-in-object-files -g main.cpp -o test
Наконец, я использую переменную среды LD_PRELOAD для предварительной загрузки общей библиотеки перед выполнением
LD_PRELOAD=./libbase.so ./test
Segmentation fault (core dumped)
Я заметил, что проблема в том, что виртуальная таблица для производного объектане определено для "Function":
(gdb) info vtbl d
vtable for 'Derived' @ 0x601030 (subobject @ 0x602010):
[0]: 0x400c7e <Derived::~Derived()>
[1]: 0x400cc0 <Derived::~Derived()>
[2]: 0x0
Я предполагаю, что когда исполняемый файл загружается, динамический компоновщик не может разрешить записи vtable, поскольку общая библиотека еще не загружена.
Итакмой вопрос: есть ли способ сделать эту работу?Возможно, заставляя каким-либо образом загрузить разделяемую библиотеку перед исполняемым файлом ...
Кстати: если сделать функцию "Function" не виртуальной, все будет работать нормально, поскольку для производного класса vtable не требуется.
UPDATE 1: Использование объекта вместо указателя заставляет main работать:
int main (int argc, char** argv)
{
Derived d;
d.Function (); // prints "base function"
return 1;
}
ОБНОВЛЕНИЕ 2: Работает так же, как в основной, но во второй общей библиотеке:
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;
}
Так что определенно проблема возникает, когда внутри исполняемого файла создается указатель нового экземпляра