app& amp;使用-static-libstdc ++构建的共享库

时间:2016-02-27 17:04:11

标签: c++ linux gcc shared-libraries libstdc++

如果我使用-static-libstdc++构建一个C ++应用程序来加载一个共享库(通过dlopen),该库也使用-static-libstdc++构建,那么应用程序会在dlopen期间出错。

但是 - 这只发生在某些设置中:

  • GCC 4.7.4,32位:传递
  • GCC 4.8.3,32位:传递
  • GCC 4.8.4,64位:传递
  • GCC 4.9.2,64位:传递
  • GCC 4.9.3,32位:失败(除非指定RTLD_DEEPBIND
  • GCC 4.9.3,64位:传递

调查结果:

  • 如果在为共享库或应用构建时未使用-static-libstdc++,则可以正常使用。
  • 如果将(RTLD_LAZY | RTLD_DEEPBIND)传递给dlopen,则可以正常工作。所以我怀疑这个问题与app& amp;之间的符号混淆/重复有关。的.so。
  • 有趣的是,如果我让代码首先使用(RTLD_LAZY | RTLD_DEEPBIND)加载.so,然后关闭它并仅使用RTLD_LAZY重新加载,它也可以。

Repro Steps

代码:

functions.cpp

extern "C"
{

  int ExportedFunction1()
  {
    std::cout << "\n---\n" << __FUNCTION__ << "\n---\n" << std::endl;
    return(0);
  }

}

的main.cpp

#include <iostream>
#include <dlfcn.h>

int main(int argc, char * argv[])
{
  void * ph(NULL);

  if(argc == 2 && argv[1][0] == '1')
  {
     std::cout << "Calling dlopen with flags RTLD_LAZY | RTLD_DEEPBIND..." << std::flush;
     ph = dlopen("./libfunctions.so", RTLD_LAZY | RTLD_DEEPBIND);
     std::cout << "done.  Result: " << ph << std::endl;
     if(ph)
        dlclose(ph);
  }

  std::cout << "Calling dlopen with flags RTLD_LAZY..." << std::flush;
  ph = dlopen("./libfunctions.so", RTLD_LAZY);
  std::cout << "done.  Result: " << ph << std::endl;
  if(ph)
       dlclose(ph);

  return 0;
}

构建

$ g++ -m32 -g -fPIC -c functions.cpp -o functions.o
$ g++ -m32 -g -fPIC -shared -Wl,-soname,libfunctions.so -static-libgcc -static-libstdc++ functions.o -o libfunctions.so
$ g++ -m32 -g -fPIC -static-libgcc -static-libstdc++ main.cpp -l dl -o main

运行

$ ./main 
Calling dlopen with flags RTLD_LAZY...Segmentation fault (core dumped)

回溯

$ gdb -c ./core ./main
GNU gdb (GDB) 7.9.1
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...done.
[New LWP 19846]

warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./main'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  __atomic_add_single (__val=1, __mem=0x0)
    at /home/test/dev/3rdParty/gcc/build/i686-pc-linux-gnu/libstdc++-v3/include/ext/atomicity.h:74
74    { *__mem += __val; }
(gdb) bt
#0  __atomic_add_single (__val=1, __mem=0x0)
    at /home/test/dev/3rdParty/gcc/build/i686-pc-linux-gnu/libstdc++-v3/include/ext/atomicity.h:74
#1  __atomic_add_dispatch (__val=1, __mem=0x0)
    at /home/test/dev/3rdParty/gcc/build/i686-pc-linux-gnu/libstdc++-v3/include/ext/atomicity.h:98
#2  _M_add_reference (this=0x0)
    at /home/test/dev/3rdParty/gcc/build/i686-pc-linux-gnu/libstdc++-v3/include/bits/locale_classes.h:510
#3  std::locale::locale (this=0xb74f7ffc <__gnu_internal::buf_cout_sync+28>)
    at /home/test/dev/3rdParty/gcc/gcc-4.9.3/libstdc++-v3/src/c++98/locale_init.cc:223
#4  0xb746f559 in basic_streambuf (this=<optimized out>)
    at /home/test/dev/3rdParty/gcc/build/i686-pc-linux-gnu/libstdc++-v3/include/streambuf:466
#5  stdio_sync_filebuf (__f=0xb76a2a20 <_IO_2_1_stdout_>, this=<optimized out>)
    at /home/test/dev/3rdParty/gcc/build/i686-pc-linux-gnu/libstdc++-v3/include/ext/stdio_sync_filebuf.h:77
#6  std::ios_base::Init::Init (this=0xb74f7a01 <std::__ioinit>)
    at /home/test/dev/3rdParty/gcc/gcc-4.9.3/libstdc++-v3/src/c++98/ios_init.cc:85
#7  0xb7469419 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535)
    at /home/test/dev/3rdParty/build_toolchain/include/c++/4.9.3/iostream:74
#8  0xb7469456 in _GLOBAL__sub_I_functions.cpp(void) () at functions.cpp:12
#9  0xb772c25e in ?? () from /lib/ld-linux.so.2
#10 0xb772c35a in ?? () from /lib/ld-linux.so.2
#11 0xb7730622 in ?? () from /lib/ld-linux.so.2
#12 0xb772c117 in ?? () from /lib/ld-linux.so.2
#13 0xb772fdf4 in ?? () from /lib/ld-linux.so.2
#14 0xb76edcae in ?? () from /lib/libdl.so.2
#15 0xb772c117 in ?? () from /lib/ld-linux.so.2
#16 0xb76ee3b6 in ?? () from /lib/libdl.so.2
#17 0xb76edd61 in dlopen () from /lib/libdl.so.2
#18 0x0804e102 in main (argc=1, argv=0xbfadc254) at main.cpp:18

对我来说很奇怪,在某些版本的GCC中,这似乎只会失败,而且仅适用于32位。我还没有尝试过GCC 5。

我很感激想法/建议。

1 个答案:

答案 0 :(得分:0)

  

如果在为共享库或应用程序构建时未使用-static-libstdc ++,则它可以正常工作。

一般情况下,您应 避免使用-static-libstdc++隐藏其所有符号以避免此类问题。

  

所以我怀疑这个问题与app&amp; amp;之间的符号混淆/重复有关。的.so。

正确。特别是,问题在于某些符号是重复的,而其他符号则不是。出于这个原因,我们必须使用disable STB_GNU_UNIQUE个符号。

  

如果我的代码首先使用(RTLD_LAZY | RTLD_DEEPBIND)加载.so,然后关闭它并仅使用RTLD_LAZY重新加载,它也可以。

这是因为dlclose如果您使用它,实际上并没有卸载库。来自man dlclose

The function dlclose() decrements the reference count on the dynamic
library handle handle.  If the reference count drops to zero and no
other loaded libraries use symbols in it, then the dynamic library
is unloaded.

您应该能够在dlclose之后停止GDB中的程序并查看其/proc/$PID/maps来验证是否是这种情况 - 您很可能会这样做发现libfunctions.so仍然存在于记忆中。