修改 glibc 动态链接器以检查共享库是不是已在另一个进程中加载

Posted

技术标签:

【中文标题】修改 glibc 动态链接器以检查共享库是不是已在另一个进程中加载【英文标题】:Modify glibc dynamic linker to check if a shared library has been loaded in another process修改 glibc 动态链接器以检查共享库是否已在另一个进程中加载 【发布时间】:2021-09-13 00:28:04 【问题描述】:

我想修改 glibc 动态链接器/加载器,以便在将共享库映射到进程之前,链接器/加载器检查该库是否已被系统中的任何其他进程加载/使用。仅当库未被任何其他进程使用/加载时,链接器/加载器才会对共享库代码执行特定操作。我知道目前链接器/加载器仅线性映射共享库并等待需求分页以物理加载库。

我尝试在动态链接器/加载器代码中使用 shell 命令lsof /path/library.so 来完成此操作。要从动态链接器代码中调用 lsof 命令,我已经尝试过

    system("lsof /path/library.so") File* fp=popen("lsof /path/library.so", "r")

但是,当我尝试包含 stdio.h(对于 popen())或 stdlib.h(对于 system())时,

构建动态链接器给了我 “x 符号的多个定义” 错误头文件。您能否建议如何解决 glibc 构建错误或任何其他更好的方法来解决我原来的问题?

附加 1:感谢@EmployedRussian。我还探讨了您提到的选项。

一个可能的答案是:将它们存储在文件或数据库中。如果这是您的答案,那么解决方案就很明显了:检查文件或数据库条目是否存在。如果是,则无需再次进行计算。

lsof 或基于文件/数据的解决方案的主要问题是:当我在该文件中添加一个新的 .c 文件和 include <stdio.h> 以执行文件操作(例如 FILE* fp = fopen())时,glibc 构建给出对于少数功能,我会出现这样的错误:'-Wl,-(' /path/glibc-2.30_build/elf/dl-allobjs.os /path/glibc-2.30_build/libc_pic.a -lgcc '-Wl,-)' -Wl,-Map,/path/glibc-2.30_build/elf/librtld.mapT /usr/bin/ld: /path/glibc-2.30_build/libc_pic.a(dl-error.os): in function `__GI__dl_signal_exception': /path/glibc_2.30_shared_library/elf/dl-error-skeleton.c:91: multiple definition of `_dl_signal_exception'; /path/glibc-2.30_build/elf/dl-allobjs.os:/path/glibc_2.30_shared_library/elf/dl-error-skeleton.c:91: first defined here

【问题讨论】:

这闻起来像XY problem - 你真正想要完成什么?你说的“对共享库代码的具体操作”是什么? 对不起,我没有谈论“具体操作”,因为我认为这不是这里问题的重点。如果这有助于更好地理解问题:在将代码部分线性映射到进程内存之后,我读取代码字节(物理加载代码页)并计算一些关于它们的统计信息。我只想在第一次物理加载库时计算一次。所以想检查共享库是否被另一个进程使用。希望对您有所帮助。 我同意 Ted 关于 XY 的观点。如果您打开.so 并读取或映射它,您可以静态剖析它的所有内容(例如使用libelfreadelf)。那么,除了使用 mmap 获得的信息之外,您还在寻找哪些额外的“动态”信息(您的“统计信息”)?通过强制页面变为常驻 [通过循环获取 mmap'ed 区域],您可以获得什么好处? 您是否考虑过如何处理加载共享对象的进程没有必要的权限甚至知道是否有任何其他进程加载了该共享对象的情况? 【参考方案1】:

但是,构建动态链接器给了我“x 符号的多个定义”错误

这是因为动态链接器非常特别,你在动态链接器中可以做的事情非常有限。

之所以特别是因为它必须是一个独立的程序——它不能使用任何其他库(包括libc.so.6)——它负责加载所有其他库,所以自然它不能使用它尚未加载的任何东西。

我只想在第一次物理加载库时计算一次。

仍然是XY Problem。你打算用这个计算的结果做什么

一个可能的答案是:将它们存储在文件或数据库中。

如果这是您的答案,那么解决方案就很明显了:检查文件或数据库条目是否存在。如果是,则无需再次进行计算。

更新:

基于 lsof 或基于文件/数据库的解决方案的主要问题是:当我添加一个新的 .c 文件并在该文件中包含 以执行文件操作时(例如 FILE* fp = fopen()) ,glibc 构建给了我错误

这是完全相同的问题:您正在尝试使用无法在动态链接器中使用的 libc.so 的部分内容。

如果要将计算结果存储在文件中,则需要使用 可用的低级部分。使用open()write() 而不是fopen()fprintf()

或者,从您的库或程序中执行此操作 - 因为您将不再关心加载了库的进程数,因此 没有理由 尝试在加载程序中执行此计算. (可能有原因,但你没有解释它;所以我们回到 XY 问题。)

【讨论】:

感谢@EmployedRussian 的回复。我用“Addition 1”编辑了主要帖子来解释我遇到的问题。 感谢@EmplyedRussian 的回答。它有效:) @ssultana -- 礼仪说明:如果答案对您有帮助,请点赞。如果它解决了您的问题,请接受它。这是你(唯一)奖励那些试图帮助你的人的方式。

以上是关于修改 glibc 动态链接器以检查共享库是不是已在另一个进程中加载的主要内容,如果未能解决你的问题,请参考以下文章

linux环境中golang使用glibc吗?

Qt 共享库(动态链接库)和静态链接库的创建及调用

链接到静态库中的 explicit_bzero (glibc)

如何知道我的程序在运行时实际使用的共享库?

centos环境升级glibc到2.17及过程中遇到的问题

关于动态库和静态库的问题。