Во-первых, вы обычно должны использовать флаг -fPIC
при создании разделяемых библиотек.
Не использовать его "работает" в 32-битной Linux, но не работает в 64-битной с ошибкой, похожей на:
/usr/bin/ld: /tmp/ccUUrz9c.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
Во-вторых, ваша программа будет работать так, как вы ожидаете, после добавления -rdynamic
в строку ссылки для основного исполняемого файла:
singleton.num in main : 100
singleton.num in hello.so : 100
singleton.num in hello.so after ++ : 101
singleton.num in main : 101
Чтобы понять, почему -rdynamic
необходимо знать о том, как динамический компоновщик разрешает символы, и о таблице символов dynamic .
Сначала давайте рассмотрим таблицу динамических символов для hello.so
:
$ nm -C -D hello.so | grep singleton
0000000000000b8c W singleton::instance()
0000000000201068 B singleton::pInstance
0000000000000b78 W singleton::singleton()
Это говорит нам о том, что есть два определения слабых функций и одна глобальная переменная singleton::pInstance
, видимая для динамического компоновщика.
Теперь давайте посмотрим на таблицу статических и динамических символов дляисходный example1
(связанный без -rdynamic
):
$ nm -C example1 | grep singleton
0000000000400d0f t global constructors keyed to singleton::pInstance
0000000000400d38 W singleton::instance()
00000000006022e0 B singleton::pInstance
0000000000400d24 W singleton::singleton()
$ nm -C -D example1 | grep singleton
$
Это верно: даже если singleton::pInstance
присутствует в исполняемом файле как глобальная переменная, этот символ не присутствует в динамическая таблица символови, следовательно, «невидим» для динамического компоновщика.
Поскольку динамический компоновщик «не знает», что example1
уже содержит определение singleton::pInstance
, он не связывает эту переменную внутри hello.so
к существующему определению (это то, что вам действительно нужно).
Когда мы добавляем -rdynamic
к строке ссылки:
$ nm -C example1-rdynamic | grep singleton
0000000000400fdf t global constructors keyed to singleton::pInstance
0000000000401008 W singleton::instance()
00000000006022e0 B singleton::pInstance
0000000000400ff4 W singleton::singleton()
$ nm -C -D example1-rdynamic | grep singleton
0000000000401008 W singleton::instance()
00000000006022e0 B singleton::pInstance
0000000000400ff4 W singleton::singleton()
Теперь определение singleton::pInstance
внутри основногоисполняемый файл видим для динамического компоновщика, и поэтому он будет «использовать» это определение при загрузке hello.so
:
LD_DEBUG=bindings ./example1-rdynamic |& grep pInstance
31972: binding file ./hello.so [0] to ./example1-rdynamic [0]: normal symbol `_ZN9singleton9pInstanceE'