3

我有一个当前动态链接到glibc. 这个库动态加载到一个应用程序中,该应用程序也动态链接到glibc. 我无法控制应用程序,只能控制共享对象。

但是,有时加载库会导致应用程序获取SIGKILLd,因为它具有非常严格的实时要求并rlimit相应地设置。用分析器查看这个告诉我,大部分时间实际上都花在了链接器上。所以本质上动态链接实际上太慢了(有时)。好吧,这不是我曾经想过的问题:)

我希望通过生成一个静态链接的共享对象来解决这个问题。但是,谷歌搜索这个问题并阅读多个其他 SO 线程警告我不要尝试静态链接 glibc。但这些似乎是 glibc 特有的问题。

所以我的问题是,如果我要静态链接这个共享库musl,然后让它(动态链接)glibc 应用程序dlopen,那会安全吗?多个libc一般有问题吗?

4

2 回答 2

4

用分析器查看这个告诉我,大部分时间实际上都花在了链接器上。

您的分析方法有很大问题。

首先,当应用程序运行时,“链接器”不会运行,只有加载器(又名 rtld,aka ld-linux)会运行。我假设您的意思不是加载程序,而不是链接器。

其次,加载程序在启动时确实有一些运行时成本,但是由于您调用的每个函数只解析一次,因此在运行任何可感知时间(超过约 1 分钟)的应用程序期间,加载程序运行时成本的比例应该很快接近零。

所以本质上动态链接实际上太慢了(有时)。

您可以要求加载器在加载时通​​过链接-Wl,-z,now器标志来解析共享库中的所有动态符号。

如果我将这个共享库与 musl 静态链接,然后让(动态链接的)glibc 应用程序 dlopen 它,那会安全吗?

这不仅不安全,而且很可能根本不起作用大多数琐碎的共享库除外)。

多个libc一般有问题吗?

将多个 libc 链接到一个进程中会导致太多问题无法计算。

更新:

在加载时解析所有符号与我想要的完全相反,因为该进程在加载共享对象期间被终止,之后它运行正常。

听起来您正在使用进程已经在dlopen 执行时间关键的实时任务。

这不是明智的做法:(dlopen除其他外)调用malloc、从磁盘读取数据、执行mmap调用等。所有这些都需要锁,并且可以等待任意长的时间。

通常的解决方案是让应用程序在进入时间关键循环之前执行初始化(加载您的库将是其中的一部分) 。

由于您无法控制应用程序,因此您唯一能做的就是告诉应用程序开发人员他们当前的需求(如果这些实际上是他们的需求)无法满足——他们必须在进入时间之前提供一些执行初始化的方法-关键部分,否则他们将始终SIGKILL. 使您的库加载速度更快只会使它SIGKILL以较低的频率出现,但不会完全删除它。

更新 2:

是的,我知道我能做的最好的事情就是降低频率而不是“解决”问题,只是试图减轻它。

您应该查看prelink。它可以显着降低执行重定位所需的时间。这不能保证您选择的预链接地址将可用,因此SIGKILL有时您可能仍会收到 ed,但这可能是一种有效的缓解措施。

于 2020-07-11T14:41:55.970 回答
3

理论上可以这样做,但是您必须编写新版本的 musl 启动代码来处理线程指针和 TCB 已经由 glibc 设置的事实,并从 ELF 运行该代码共享对象中的构造函数。由于 TCB 布局差异,某些 musl 功能将不可用。

我认为这不太可能解决您的实际问题。即使它与时间相关,这种 hack 也有可能使事情变得更糟,因为它增加了所需的运行时重定位量。

于 2020-07-12T15:47:32.577 回答