动态链接的 glibc 应用程序 dlopen() 可以是静态链接的 musl 共享对象吗?
Can a dynamically linked glibc application dlopen() a static linked musl shared object?
我有一个当前针对 glibc
动态 link 编辑的库。
该库动态加载到应用程序中,该应用程序也针对 glibc
动态 linked。我无法控制应用程序,只能控制共享对象。
但是,有时加载库会导致应用程序获得 SIGKILL
d,因为它具有非常严格的实时要求并且相应地设置了 rlimit
s。用分析器看这个告诉我大部分时间实际上花在 linker 上。所以本质上动态 linking 实际上太慢了(有时)。好吧,这不是我曾经想过的问题:)
我希望通过生成静态 linked 共享对象来解决这个问题。但是,谷歌搜索这个问题并阅读多个其他 SO 线程警告我不要尝试静态 link glibc。但这些似乎是 glibc 特定的问题。
所以我的问题是,如果我要针对 musl
静态 link 这个共享库,然后让一个(动态 linked)glibc 应用程序 dlopen
它,那会安全吗?多个 libc 是否存在一般问题?
Looking at this with a profiler tells me that most of the time is actually spent in the linker.
您的分析方法非常有问题。
首先,当应用程序 运行 时,“链接器”不会 运行,只有 loader(又名 rtld,又名 ld-linux
) 做。我假设你的意思不是加载器,而不是链接器。
其次,加载器在启动时确实有一些运行时间成本,但是由于您调用的每个函数只被解析一次,加载程序的比例 运行 应用程序持续时间的时间成本 运行s 对于任何可观的时间(超过大约 1 分钟)应该很快接近零。
So essentially dynamic linking is actually too slow (sometimes).
您可以要求加载程序在加载时通过使用 -Wl,-z,now
链接器标志进行链接来解析共享库中的所有动态符号。
if I were to statically link this shared library against musl and then let a (dynamically linked) glibc application dlopen it, would that be safe?
这不仅不安全,而且很可能根本无法工作(大多数琐碎的共享库除外)。
Is there a problem in general with multiple libc's?
将多个 libc 链接到一个进程中会导致无法计数的问题。
更新:
resolving all symbols at load time is exactly the opposite of what I want, as the process gets sigkilled during loading of the shared object, after that it runs fine.
听起来您正在使用 dlopen
而 该进程 已经 执行时间关键的实时任务。
这不是明智之举:dlopen
(除其他外)调用 malloc
、从磁盘读取数据、执行 mmap
调用等 所有这些都需要锁,并且可以等待任意长的时间。
通常 解决方案是让应用程序执行初始化(加载您的库将是其中的一部分)在 进入时间关键之前循环。
由于您无法控制应用程序,您唯一能做的就是告诉应用程序开发人员他们当前的要求(如果这些实际上是他们的要求)是不可满足的——他们必须提供一些方法来满足在进入时间关键部分之前执行初始化,否则他们将 总是 冒 SIGKILL
的风险。使您的库加载速度更快只会使 SIGKILL
出现的频率降低,但不会将其完全删除。
更新二:
yes, i'm aware that the best I can do is lower the frequency and not "solve" the problem, only try to mitigate it.
你应该调查一下 prelink。它可以大大减少执行重定位所需的时间。这不能保证您选择的预链接地址可用,因此您有时可能仍会收到 SIGKILL
ed,但这可能是一种有效的缓解措施。
理论上可以做类似的事情,但是你必须编写一个新版本的 musl 启动代码来处理线程指针和 TCB 已经由 glibc 设置的事实,并且 运行 该代码来自共享对象中的 ELF 构造函数。由于 TCB 布局差异,一些 musl 功能将不可用。
我认为这不太可能解决您的实际问题。即使它与时间相关,这个 hack 也可能使事情变得更糟,因为它 增加了 所需的 运行 时间重定位的数量。
我有一个当前针对 glibc
动态 link 编辑的库。
该库动态加载到应用程序中,该应用程序也针对 glibc
动态 linked。我无法控制应用程序,只能控制共享对象。
但是,有时加载库会导致应用程序获得 SIGKILL
d,因为它具有非常严格的实时要求并且相应地设置了 rlimit
s。用分析器看这个告诉我大部分时间实际上花在 linker 上。所以本质上动态 linking 实际上太慢了(有时)。好吧,这不是我曾经想过的问题:)
我希望通过生成静态 linked 共享对象来解决这个问题。但是,谷歌搜索这个问题并阅读多个其他 SO 线程警告我不要尝试静态 link glibc。但这些似乎是 glibc 特定的问题。
所以我的问题是,如果我要针对 musl
静态 link 这个共享库,然后让一个(动态 linked)glibc 应用程序 dlopen
它,那会安全吗?多个 libc 是否存在一般问题?
Looking at this with a profiler tells me that most of the time is actually spent in the linker.
您的分析方法非常有问题。
首先,当应用程序 运行 时,“链接器”不会 运行,只有 loader(又名 rtld,又名 ld-linux
) 做。我假设你的意思不是加载器,而不是链接器。
其次,加载器在启动时确实有一些运行时间成本,但是由于您调用的每个函数只被解析一次,加载程序的比例 运行 应用程序持续时间的时间成本 运行s 对于任何可观的时间(超过大约 1 分钟)应该很快接近零。
So essentially dynamic linking is actually too slow (sometimes).
您可以要求加载程序在加载时通过使用 -Wl,-z,now
链接器标志进行链接来解析共享库中的所有动态符号。
if I were to statically link this shared library against musl and then let a (dynamically linked) glibc application dlopen it, would that be safe?
这不仅不安全,而且很可能根本无法工作(大多数琐碎的共享库除外)。
Is there a problem in general with multiple libc's?
将多个 libc 链接到一个进程中会导致无法计数的问题。
更新:
resolving all symbols at load time is exactly the opposite of what I want, as the process gets sigkilled during loading of the shared object, after that it runs fine.
听起来您正在使用 dlopen
而 该进程 已经 执行时间关键的实时任务。
这不是明智之举:dlopen
(除其他外)调用 malloc
、从磁盘读取数据、执行 mmap
调用等 所有这些都需要锁,并且可以等待任意长的时间。
通常 解决方案是让应用程序执行初始化(加载您的库将是其中的一部分)在 进入时间关键之前循环。
由于您无法控制应用程序,您唯一能做的就是告诉应用程序开发人员他们当前的要求(如果这些实际上是他们的要求)是不可满足的——他们必须提供一些方法来满足在进入时间关键部分之前执行初始化,否则他们将 总是 冒 SIGKILL
的风险。使您的库加载速度更快只会使 SIGKILL
出现的频率降低,但不会将其完全删除。
更新二:
yes, i'm aware that the best I can do is lower the frequency and not "solve" the problem, only try to mitigate it.
你应该调查一下 prelink。它可以大大减少执行重定位所需的时间。这不能保证您选择的预链接地址可用,因此您有时可能仍会收到 SIGKILL
ed,但这可能是一种有效的缓解措施。
理论上可以做类似的事情,但是你必须编写一个新版本的 musl 启动代码来处理线程指针和 TCB 已经由 glibc 设置的事实,并且 运行 该代码来自共享对象中的 ELF 构造函数。由于 TCB 布局差异,一些 musl 功能将不可用。
我认为这不太可能解决您的实际问题。即使它与时间相关,这个 hack 也可能使事情变得更糟,因为它 增加了 所需的 运行 时间重定位的数量。