gpt4 book ai didi

c++ - 使用 RTLD_DEEPBIND 动态加载共享库

转载 作者:行者123 更新时间:2023-11-30 05:27:29 34 4
gpt4 key购买 nike

背景:我有应用程序的一部分用作其他独立应用程序的库。他们在链接时链接到那个库(比方说 lib.so)。这种方法的问题是我们必须使用相同的外部库,如 boost、ace 等,否则我们将有重复的符号,最终会导致崩溃。我们想解决这个问题。

我知道两种技术 - 一种是隐藏所有符号(不确定共享库的全局/局部范围的顺序),另一种是使用动态链接。我们选择了第二个选项(动态链接),因为它让客户有机会使用 stub lib.so 进行简单测试。我们有非常简单的 API。

我在下面写了一个应用程序的小例子,它加载了示例共享库并且它崩溃了(我想了解它崩溃的原因以及它应该如何编写)。崩溃发生在 dlopen 中,恰好在分配给 std::string(Aclass 类型的构造函数)时全局变量的初始化中。从我们的测试来看,在库的持续初始化过程中对 std 库的任何访问都将导致崩溃。

我们通过向 EXECUTABLE 添加 -fPIcflags设法消除了崩溃(为什么这解决了我们的问题,我认为它应该为共享库设置,谁能更准确地解释我)?就我的理解而言,这个标志是不必要的,因为它会减慢应用程序的速度,并且在我的情况下(低延迟应用程序)这是非常有问题的。

总结:1.为什么会出现这个crash?2. 为什么 -fPIcflags足以解决此崩溃问题?3. 为什么将-fPIcflags设置为可执行文件就足够了?4. 是否有可能以其他方式解决我的问题,以便共享库和客户端应用程序可以使用不同版本的库(如 boost、ace 等,编译器、linux 版本和 std 库保证相同)?5. 删除标志 RTLD_DEEPBIND 也将修复崩溃,但从 gcc man 看来我应该使用此标志,因为它将更改共享库的符号范围顺序 - 首先它将在本地范围内搜索符号,然后在全局范围内搜索符号 - 看起来对我来说是必须的因为共享库将使用与可执行文件不同的外部库(并且动态加载将通过污染其符号范围来保护可执行文件)。为什么在这个简单的案例中删除这个标志修复崩溃?

共享库 dynLib.cpp:

#include <string>
class Aclass
{
std::string s;
s = "123";
}

Aclass a;

可执行的main.cpp:

#include <stdlib.h>
#include <dlfcn.h>
#include <string>
#include <unistd.h>
#include <iostream>

int main()
{
std::string dummyCrasher;
dlerror();
void* handle = dlopen("./libdynLib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
if(!handle)
{
std::cout << "handle is null" << dlerror();
}

usleep(1000 * 1000 * 10);
}

生成文件:生成文件

CXXFLAGS=-m32 -march=x86-64 -Wl,v -g -O3 -Wformat -Werror=format -c
CLINKFLAGS=-Wl,-Bstatic -Wl,Bdynamic -ldl -m32 -march=x86-64

all: dynLib.so dynamiclinking

dynLib.so: dynLib.o
g++44 $(CLINKFLAGS) -shared -o libdynLib.so dynLib.o

dynLib.o: dynLib.cpp
g++44 $(CXXFLAGS) dynLib.cpp

dynamiclinking: main.o
g++44 $(CLINKFLAGS) -o dynamiclinking main.o -ldl

main.o: main.cpp
g++44 (CXXFLAGS) main.cpp

.PHONY: clean
clean:
rm dynLib.o main.o dynamiclinking libdynLib.so

附言。我手写代码(可能会出现一些拼写错误)PS 2. 使用 -fPIcflags它会起作用:

main.o: main.cpp
g++44 (CXXFLAGS) main.cpp -fPIC

更新可以通过 libstdc++ 的静态链接来解决这个问题。但是我的问题仍然没有得到解答 :( 也许有人有时间看一下?

UPDATE2 GCC 4.4.6 和 4.8.1 出现同样的问题。

最佳答案

我认为您遇到的问题与 When we are supposed to use RTLD_DEEPBIND? 中的问题相同,其中可执行文件获取全局变量的拷贝:

well that's a wonderful feature of you building the main application without the -fPIC option. [...] This means that when the symbol is found in libdep.so, it gets copied into the initial data segment of the main executable at that address. Then the reference to duplicate in libdep.so is looked up and it points to the copy of the symbol that's in the main executable.

由于 RTLD_DEEPBIND,dynLib.so 在初始化 std::string 时从原始 libstdc++ 中看到错误的全局变量集,因此崩溃。

至于为什么链接器有这样的行为,this article有详细的解释(强调我的):

Recall that the program/executable is not relocatable, and thus its data addresses have to bound at link time. Therefore, the linker has to create a copy of the variable in the program's address space, and the dynamic loader will use that as the relocation address. This is similar to the discussion in the previous section - in a sense, myglob in the main program overrides the one in the shared library, and according to the global symbol lookup rules, it's being used instead.

最后一点:这种行为是特定于平台的,至少在 PowerPC 上,主可执行文件中没有这样的全局变量的额外拷贝。

关于c++ - 使用 RTLD_DEEPBIND 动态加载共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37296995/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com