g++与共享库和libpthread的问题。

时间:2021-11-25 13:27:28

I've hit a wall with this issue and I'm hoping I can find some help here with this issue. I've created a small sample executable and shared library that exhibits the problem.

我在这个问题上遇到了瓶颈,我希望能在这个问题上找到一些帮助。我创建了一个小的可执行和共享库示例,展示了这个问题。

Sorry, I realize this has turned into a wall of text, but I was trying to make sure to include all the relevant information.

对不起,我意识到这已经变成了一堆文本,但我试图确保包含所有相关的信息。

My Setup

我的设置

System: CentOS release 5.11 (Final)
g++: gcc version 4.4.7 20120313 (Red Hat 4.4.7-1) (GCC) 
libc.so.6: Compiled by GNU CC version 4.1.2 20080704 (Red Hat 4.1.2-55).

I have also tried this on a Redhat 6.6 machine with similar results.

我也在Redhat 6.6机器上尝试过,结果也差不多。

My scenario:

我的情况:

I have an application that is trying to load a shared library at runtime via ::dlopen(). If I don't link in pthread then it appears to work but it will eventually crash in the shared library trying to throw an exception. The reason for this is that the system runtime libraries were built expecting thread local storage (TLS) and the exception processing uses a data structure from TLS but in this case it's NULL and it causes a crash. The functions are __cxa_allocate_exception and __cxa_get_globals, and it looks like they are using the stub functions from libc since pthread isn't linked in.

我有一个应用程序试图在运行时通过::dlopen()来加载共享库。如果我在pthread中没有链接,那么它看起来会起作用,但它最终会在共享库中崩溃,试图抛出异常。原因是系统运行时库的构建期望线程本地存储(TLS),而异常处理使用来自TLS的数据结构,但在这种情况下,它是NULL,并导致崩溃。函数是__cxa_allocate_exception和__cxa_get_globals,看起来它们使用的是来自libc的存根函数,因为pthread没有链接到其中。

The problem I'm having now is trying to link in pthread to correct the issue mentioned above. If I build with pthreads, the application segfaults trying to load libpthread.so.0 as a dependency of my shared library. Everything I've read about this crash is that the the application was built without pthread while the shared library was built with pthread. However I'm building both binaries with pthreads and I still experience the issue.

我现在遇到的问题是试图链接到pthread来纠正上面提到的问题。如果我使用pthreads构建,应用程序分段错误将试图加载libpthread.so。0作为共享库的依赖项。我所读到的关于这次崩溃的所有内容是,在共享库构建pthread时,应用程序是没有pthread构建的。然而,我正在用pthreads构建两个二进制文件,我仍然会遇到这个问题。

Sample Code:

示例代码:

Shared Library Files (foo.*)

共享库文件(foo . *)

foo.h

foo。

#pragma once
extern "C"
{
    extern void DoWork();
}

foo.cpp

foo.cpp

#include "foo.h"
#include <stdio.h>

void DoWork()
{
    printf( "SharedLibrary::DoWork()\n" );
}

Application File (main.cpp)

应用程序文件(main.cpp)

main.cpp

main.cpp

#include "foo.h"
#include <stdio.h>
#include <dlfcn.h>

void LoadSharedLibrary()
{
    void* handle = 0;
    void(*function)();

    try
    {
        printf( "Loading the shared library\n" );
        handle = ::dlopen( "libfoo.so", 2 );
        function = (void (*)())::dlsym( handle, "DoWork" );
        printf( "Done loading the shared library\n" );

        function();
    }
    catch(...)
    {
        printf( "ERROR - Exception while trying to load the shared library\n" );
    }
}

int main(int argc, char* argv[])
{
    LoadSharedLibrary();
    return 0;
}

Explicit Loading

显式加载

Trying to load the shared library at runtime using the following build script results in a segfault trying to load libpthread.so.0.

尝试在运行时使用以下构建脚本加载共享库,会导致试图加载libpthread.so.0的分段错误。

Build script:

构建脚本:

compiler=g++
arch=-m32
echo gcc architecture flag: ${arch}

${compiler} -c -fPIC -g ${arch} -pthread -o ./foo.o foo.cpp
${compiler} ${arch} -shared -g -o ./libfoo.so ./foo.o -lpthread

${compiler} -c -fPIC -g ${arch} -pthread -o ./main.o main.cpp
${compiler} ${arch} -static -g -o main.out ./main.o -lpthread -ldl -lc 

The stack trace for this crash is:

这次崩溃的堆栈跟踪是:

#0  0x00000000 in ?? ()
#1  0x0089a70a in __pthread_initialize_minimal_internal () at init.c:417
#2  0x0089a218 in call_initialize_minimal () from /lib/libpthread.so.0
#3  0x00899da8 in _init () from /lib/libpthread.so.0
#4  0x0808909b in call_init ()
#5  0x080891b0 in _dl_init ()
#6  0x08063a87 in dl_open_worker ()
#7  0x0806245a in _dl_catch_error ()
#8  0x0806349e in _dl_open ()
#9  0x08053106 in dlopen_doit ()
#10 0x0806245a in _dl_catch_error ()
#11 0x08053541 in _dlerror_run ()
#12 0x08053075 in __dlopen ()
#13 0x0804830f in dlopen ()
#14 0x0804824f in LoadSharedLibrary () at main.cpp:13
#15 0x080482d3 in main (argc=1, argv=0xffffd3e4) at main.cpp:27

The loaded shared libraries are:

已加载的共享库如下:

From        To          Syms Read   Shared Object Library
0xf7ffb3b0  0xf7ffb508  Yes         libfoo.so
0x0089a210  0x008a5bc4  Yes (*)     /lib/libpthread.so.0
0xf7f43670  0xf7fbec24  Yes (*)     /usr/lib/libstdc++.so.6
0x009a8410  0x009c35a4  Yes (*)     /lib/libm.so.6
0xf7efb660  0xf7f02f34  Yes (*)     /lib/libgcc_s.so.1
0x0074dcc0  0x0084caa0  Yes (*)     /lib/libc.so.6
0x007197f0  0x0072f12f  Yes (*)     /lib/ld-linux.so.2
(*): Shared library is missing debugging information.

Implicit Loading

隐式加载

This uses a different build script that tries to setup the dependency at build time and would in theory not require an explicit load call. This isn't a valid use case for our real world scenario, but I tried to do this while looking into this issue.

这使用了一个不同的构建脚本,该脚本试图在构建时设置依赖项,理论上不需要显式的加载调用。对于我们的真实场景来说,这不是一个有效的用例,但是我在研究这个问题时尝试这么做。

Build Script:

构建脚本:

compiler=g++
arch=-m32
echo gcc architecture flag: ${arch}

${compiler} -c -fPIC -g ${arch} -pthread -o ./foo.o foo.cpp
${compiler} ${arch} -shared -g -o ./libfoo.so ./foo.o -lpthread

${compiler} -c -fPIC -g ${arch} -pthread -o ./main.o main.cpp
${compiler} ${arch} -static -g -L. -o main.out ./main.o -lpthread -ldl -Wl,-Bdynamic -lfoo -Wl,-static -lc

Behavior:

行为:

Starting program: /app_local/dev3/stack_overflow/main.out 
/bin/bash: /app_local/dev3/stack_overflow/main.out: /usr/lib/libc.so.1: bad ELF interpreter: No such file or directory
/bin/bash: /app_local/dev3/stack_overflow/main.out: Success

During startup program exited with code 1.

在启动程序中退出代码1。

The weird thing is that I've done objdump -p <library> | grep NEEDED and none of the libraries in the dependency chain have libc.so.1 as a dependency. The version of libc they depend on is libc.so.6.

奇怪的是,我已经完成了objdump -p | grep,并且依赖链中的所有库都没有libc.so。1作为一个依赖项。他们所依赖的libc的版本是libc.so.6。

End of build scenarios

构建场景结束

I'm really hoping somebody here has an idea about what is going on and could help me out. My Google and * skills have failed me as everything I've found points to mismatched pthread usage as the root problem.

我真的希望这里有人能知道发生了什么,能帮助我。我的谷歌和*技巧使我失败了,因为我找到的所有东西都指向错误匹配的pthread用法作为根本问题。

Thanks in advance!

提前谢谢!

1 个解决方案

#1


2  

${compiler} ${arch} -static -g -o main.out ./main.o -lpthread -ldl -lc

${编译}${arch} -静态-g -o main。/主要。o -lpthread ldl lc

This is a fully-static link.

这是一个完全静态的链接。

On most OSes, no calls to dlopen can be made from a fully-static binary (dlopen is simply not provided in libdl.a, and the link fails).

在大多数操作系统中,不能从完全静态的二进制文件中调用dlopen(在libdl中根本没有提供dlopen。a,链接失败)。

GLIBC is an exception, but only so far as dlopen is needed to support /etc/nsswitch.conf. Almost certainly dynamic loading of libpthread.so.0 into a fully-static a.out that contains its own copy of libpthread.a is not supported. The short answer is: it hurts, don't do that.

GLIBC是一个例外,但是只需要dlopen来支持/etc/nsswitch.conf。几乎可以肯定的是libpthreadso的动态加载。0变成一个完全静态的a。它包含自己的libpthread副本。不支持。简短的回答是:这很伤人,别那么做。

Fully-static linking is in general a very bad idea on any modern UNIX system. Fully-static linking of multithreaded apps doubly so. Fully-static linking that then dynamically loads another copy of libpthread? Really bad idea.

在任何现代UNIX系统中,完全静态链接都是一个非常糟糕的想法。多线程应用程序的全静态链接更是如此。然后动态加载libpthread的另一个副本的完全静态链接?非常糟糕的主意。

Update:

更新:

GLIBC consists of many libraries (200+), and I would strongly advise against mixing static and dynamic linking for any such library. In other words, if you link against libc.a, then make it a completely static link. If you link against libc.so, then don't statically link libpthread.a, libdl.a, or any other part of GLIBC.

GLIBC由许多库(200+)组成,我强烈建议不要将静态和动态链接放在任何这样的库中。换句话说,如果你链接到libc。a,然后把它变成一个完全静态的链接。如果你链接到libc。所以,不要静态地链接libpthread。libdl。a或GLIBC的任何其他部分。

#1


2  

${compiler} ${arch} -static -g -o main.out ./main.o -lpthread -ldl -lc

${编译}${arch} -静态-g -o main。/主要。o -lpthread ldl lc

This is a fully-static link.

这是一个完全静态的链接。

On most OSes, no calls to dlopen can be made from a fully-static binary (dlopen is simply not provided in libdl.a, and the link fails).

在大多数操作系统中,不能从完全静态的二进制文件中调用dlopen(在libdl中根本没有提供dlopen。a,链接失败)。

GLIBC is an exception, but only so far as dlopen is needed to support /etc/nsswitch.conf. Almost certainly dynamic loading of libpthread.so.0 into a fully-static a.out that contains its own copy of libpthread.a is not supported. The short answer is: it hurts, don't do that.

GLIBC是一个例外,但是只需要dlopen来支持/etc/nsswitch.conf。几乎可以肯定的是libpthreadso的动态加载。0变成一个完全静态的a。它包含自己的libpthread副本。不支持。简短的回答是:这很伤人,别那么做。

Fully-static linking is in general a very bad idea on any modern UNIX system. Fully-static linking of multithreaded apps doubly so. Fully-static linking that then dynamically loads another copy of libpthread? Really bad idea.

在任何现代UNIX系统中,完全静态链接都是一个非常糟糕的想法。多线程应用程序的全静态链接更是如此。然后动态加载libpthread的另一个副本的完全静态链接?非常糟糕的主意。

Update:

更新:

GLIBC consists of many libraries (200+), and I would strongly advise against mixing static and dynamic linking for any such library. In other words, if you link against libc.a, then make it a completely static link. If you link against libc.so, then don't statically link libpthread.a, libdl.a, or any other part of GLIBC.

GLIBC由许多库(200+)组成,我强烈建议不要将静态和动态链接放在任何这样的库中。换句话说,如果你链接到libc。a,然后把它变成一个完全静态的链接。如果你链接到libc。所以,不要静态地链接libpthread。libdl。a或GLIBC的任何其他部分。