-rdynamic не работает при использовании dlopen из статического бинарного файла - PullRequest
0 голосов
/ 22 ноября 2018

Работая на встроенном устройстве (ARM, uClibc), у меня есть статический исполняемый файл, который статически связан с различными библиотеками, и имеет функцию динамической загрузки с использованием dlopen.

set(EXTERNAL_LIBS "-lpthread -lpcap -lcurl -ldl")    
target_link_libraries(myApp -static ${EXTERNAL_LIBS})

При загрузке простого плагина все отлично работает .

void plugin::execute() {
   std::cout << "hello world" << std::endl;
}

При добавлении строковой переменной:

void plugin::execute() {
    //THIS IS NOT WORKING
    std::string test = "hello world from thing";
    std::cout << test << std::endl;
}

Я получаю:

"не удается разрешить символ '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_'"

Я пытался добавить -rdynamic , как предлагается здесь: Отбрасывание динамической библиотеки из статической библиотеки, когда динамическая библиотека используетсимволы статического , добавив:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic  -Wl,-export-dynamic")

Но он все еще не работает.

Отсутствующий символ ДОЛЖЕН существовать в статическом двоичном файле (проверяется с использованием nm)

Что мне здесь не хватает ??


Добавлен упрощенный вывод процесса сборки:

Компиляция объектных файлов

arm-linux-uclibcgnueabi-g++  -fPIC   -std=gnu++98  -o CMakeFiles/libstaticlib.dir/test1.cpp.o   -c /work/src/test1.cpp
arm-linux-uclibcgnueabi-gcc  -fPIC   -std=gnu++98  -o CMakeFiles/libstaticlib.dir/test2.cpp.o   -c /work/src/test2.cpp

Связывание статической библиотеки CXX

arm-linux-uclibcgnueabi-ar qc libstaticlib.a  CMakeFiles/libstaticlib.dir/test1.cpp.o CMakeFiles/libstaticlib.dir/test2.cpp.o
arm-linux-uclibcgnueabi-ranlib libstaticlib.a

Компиляция myApp

arm-linux-uclibcgnueabi-g++   -fPIE   -std=gnu++98 -o CMakeFiles/myapp.dir/main.cpp.o -c /work/src/main.cpp

Связывание исполняемого файла CXX

arm-linux-uclibcgnueabi-g++   -rdynamic CMakeFiles/myapp.dir/main.cpp.o  -o myapp  -L/work/lib -Wl,-rpath,/work/lib -rdynamic -static libstaticlib.a -lpthread -lpcap -lcurl -ldl

Плагин компиляции

arm-linux-uclibcgnueabi-g++  -fPIC   -std=gnu++98 -o CMakeFiles/plugin.dir/plugin/plugin.cpp.o -c /work/src/plugins/plugin/plugin.cpp

Связывание общей библиотеки CXX ../libplugin.so

arm-linux-uclibcgnueabi-g++  -fPIC   -shared -Wl,-soname,libplugin.so -o ../libplugin.so CMakeFiles/plugin.dir/plugin/plugin.cpp.o  -L/work/lib

вывод readelf -s myapp |grep ...:

 0021ce74    68 FUNC    WEAK   DEFAULT    2 _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_

1 Ответ

0 голосов
/ 22 ноября 2018

-rdynamic является опцией GCC .Таким образом, вы можете передать его непосредственно в GCC, когда он вызывает компоновщик (ld).Эффект -rdynamic заключается в том, что GCC передает --export-dynamic при вызове ld, как вы можете видеть в руководстве GCC: 3.14 Параметры для связывания

--export-dynamicне является опцией GCC, но является опцией ld .Вы можете указать GCC пропустить эту опцию, когда она вызывает ld, передав -Wl,--export-dynamic в GCC.

Таким образом, ваши параметры GCC:

-rdynamic  -Wl,-export-dynamic

делают одно и то же дважды: -rdynamic было бы достаточно.

Но установка:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")

не заставит GCC передавать -rdynamic, когда он вызывает компоновщик.

Это потому, что CMAKE_CXX_FLAGS устанавливает параметры, которые будут переданы каждой компиляции C ++ .Поскольку при компиляции не происходит связывание, параметры связывания игнорируются и не имеют никакого эффекта.Параметры связи должны быть установлены в CMAKE_EXE_LINKER_FLAGS, например:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")

Но даже тогда ...

заголовок вашего вопросаостанется верным, потому что -rdynamic не работает из статического двоичного файла , точка.

со страницы руководства компоновщика

- export-dynamic

При создании динамически связанного исполняемого файла использование параметра -E или параметра --export-dynamic приводит к тому, что компоновщик добавляет все символы в таблицу динамических символов..

Мой акцент.И вы не создаете динамически связанный исполняемый файл, потому что вы связываете -static.Не будет динамической таблицы символов, в которую можно добавить все символы.

Вот элементарная демонстрация.

main.c

int foo() {
    return 0;
}

int main()
{
    return foo();
}

Компилировать и связывать как обычно:

$ gcc main.c

Динамическая таблица символов:

$ nm -D a.out 
                 w __cxa_finalize
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main

Компилировать и связывать -rdynamic;см. динамическую таблицу символов:

$ gcc -rdynamic main.c
$ nm -D a.out 
0000000000201010 B __bss_start
                 w __cxa_finalize
0000000000201000 D __data_start
0000000000201000 W data_start
0000000000201010 D _edata
0000000000201018 B _end
0000000000000884 T _fini
00000000000007ea T foo
                 w __gmon_start__
00000000000006a0 T _init
0000000000000890 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000880 T __libc_csu_fini
0000000000000810 T __libc_csu_init
                 U __libc_start_main
00000000000007f5 T main
00000000000006e0 T _start

Теперь больше символов, включая main и foo.

Компиляция и ссылка -static;см. динамическую таблицу символов:

$ gcc -static main.c
$ nm -D a.out 
nm: a.out: no symbols

И наконец:

$ gcc -rdynamic -static main.c
$ nm -D a.out 
nm: a.out: no symbols

Вы просто не можете статически связать программу, если хотите, чтобы плагин ссылался на определяемые им символы.

...