从静态二进制文件使用dlopen时,-rdynamic不起作用

时间:2018-11-22 12:26:03

标签: c++ static-libraries dynamic-linking dynamic-loading

在嵌入式设备(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 dlopen a dynamic library from a static library, when the dynamic library uses symbols of the static one 通过添加:

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 :(得分:2)

-rdynamic是GCC linkage 选项。所以你可以直接传递给 GCC调用链接器(ld)时。 -rdynamic的作用是 您可能会看到,GCC在调用--export-dynamic时通过了ldGCC manual: 3.14 Options for Linking

--export-dynamic不是GCC选项,而是ld option。您 可以通过传递ld告诉GCC在调用-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 在静态二进制句点中无效。

linker man page

  

-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

现在有更多符号,包括mainfoo

编译并链接-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

如果要让插件引用其定义的符号,则无法静态链接程序。