【问题标题】:-rdynamic doesn't work when using dlopen from static binary从静态二进制文件使用 dlopen 时 -rdynamic 不起作用
【发布时间】:2019-04-25 03:20:57
【问题描述】:

在嵌入式设备(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_'”

我已尝试按照此处的建议添加 -rdynamicdlopen 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

编译我的应用程序

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_

【问题讨论】:

  • “缺少的符号确实存在于静态二进制文件中(使用 nm 验证)”。请添加readelf --dyn-syms myapp | grep _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_的实际输出作为证据
  • readelf --dyn-syms myapp 没有输出(可能是因为 myapp 是静态的?) nm 给出以下信息:0021ce74 W ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3
  • nm 正在向您展示全局符号表。 nm -D 将显示动态符号表,它不会在那里。尽管有-rdynamic,但它没有被导出用于动态链接,但没有你的代码或minimal reproducible example,这是我所能得到的,抱歉。
  • 想通了,学到了一些东西。查看更新的答案。

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


【解决方案1】:

-rdynamic 是一个 GCC 链接 选项。所以你可以直接将它传递给 GCC 在调用链接器时 (ld)。 -rdynamic 的效果是 让 GCC 在调用 ld 时通过 --export-dynamic,如您所见 在GCC manual: 3.14 Options for Linking

--export-dynamic 不是 GCC 选项,而是ld option。你 可以通过传递 -Wl,--export-dynamic 来告诉 GCC 在调用 ld 时传递此选项 到 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

--动态导出

创建动态链接的可执行文件时,使用 -E 选项或 --export-dynamic 选项使链接器将所有符号添加到动态符号表中。

我的重点。而且您没有创建动态链接的可执行文件,因为您 正在链接-static。将不会有一个动态符号表,所有符号都在其中 可以添加。

这是一个基本的演示。

ma​​in.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

如果您希望插件引用它定义的符号,则不能静态链接程序。

【讨论】:

  • @MukiD :( 你最好用make VERBOSE=1从头开始清理和重建你的项目,然后编辑你的帖子以显示完整的输出,这样我们就可以看到真正发生了什么。
  • 感谢您的演示。你有一些解决方法的想法吗?我正在使用静态二进制文件来避免不同平台上的依赖问题
  • 是否可以创建一个包含所有“myApp”依赖项(包括 uclibc)的共享库?并动态链接 myApp?
  • @MukiD 仅当您拥有所有这些依赖项的静态库时,递归地,其内容已编译-fPIC,以便可链接到您的厨房水槽共享库。我不认为你会找到这些,或者自己制作它们是可行的。
猜你喜欢
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-02
  • 2015-05-13
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
相关资源
最近更新 更多