我有一个在启动时加载 .so 文件作为插件的应用程序,使用
dlopen()
构建环境在 x86 硬件上运行,但应用程序正在针对另一个平台进行交叉编译。
如果我可以(作为自动构建过程的一部分)进行检查以确保 .so 文件和应用程序的组合中不存在任何未解析的符号,而无需实际部署应用程序,那就太好了.
在我编写一个使用
nm
的输出测试符号的脚本之前,我想知道是否有人知道已经执行此操作的实用程序?
编辑 1:稍微更改了描述 - 我不只是尝试测试 .so 中的符号,而是测试几个 .so 和应用程序本身的组合 - 即。应用程序加载所有 .so 后是否仍然存在未解析的符号。
正如答案中所建议的(感谢 Martin v. Löwis 和 tgamblin),
nm
将轻松识别单个文件中丢失的符号,但无法轻松识别哪些符号已在其他加载的模块之一中解析。
理想情况下,跨纳米工具是交叉编译器套件的一部分。例如,如果您构建 GNU binutils 进行交叉编译,也会提供 cross-nm(以及 cross-objdump)。
nm
中的限制意味着它不可能用于全面的符号检查器。
特别是,nm
只会列出导出的符号。
但是,
readelf
将生成一个全面的列表,以及所有库依赖项。
使用
readelf
可以构建一个脚本:
创建所有使用的库的列表,
在可执行文件(或 .so)中构建符号列表
建立未解析符号的列表 - 如果此时存在任何未解析符号,则在加载时会出现错误。
然后重复此操作,直到找不到新的库。
如果对可执行文件和所有
dlopen()
ed .so 文件执行此操作,它将很好地检查运行时遇到的未解决的依赖关系。
您可以为此使用 ldd 的递归版本吗?有人似乎已经写了一个脚本可能会有所帮助。这至少告诉您,如果首先在 .so 中正确指定了所有依赖库,则可以解析它们。您可以保证使用链接器选项在 .so 中引用所有依赖项,并且这加上递归 ldd 将保证您没有未解析的符号。
链接器通常可以选择将共享库中未解析的符号设置为错误,您可以使用它来避免进行检查。对于 GNU ld,你可以只传递 --no-allow-shlib-undefined 并且保证如果它生成 .so,它不会有未解析的符号。来自 GNU ld 文档:
--no-undefined
Report unresolved symbol references from regular object files.
This is done even if the linker is creating a non-symbolic shared
library. The switch --[no-]allow-shlib-undefined controls the
behaviour for reporting unresolved references found in shared
libraries being linked in.
--allow-shlib-undefined
--no-allow-shlib-undefined
Allows (the default) or disallows undefined symbols in shared
libraries. This switch is similar to --no-undefined except
that it determines the behaviour when the undefined symbols are
in a shared library rather than a regular object file. It does
not affect how undefined symbols in regular object files are
handled.
The reason that --allow-shlib-undefined is the default is that the
shared library being specified at link time may not be the
same as the one that is available at load time, so the symbols might
actually be resolvable at load time. Plus there are some systems,
(eg BeOS) where undefined symbols in shared libraries is normal.
(The kernel patches them at load time to select which function is most
appropriate for the current architecture. This is used for example to
dynamically select an appropriate memset function). Apparently it is
also normal for HPPA shared libraries to have undefined symbols.
如果您打算进行链接后检查,我同意 Martin 的观点,nm 可能是您最好的选择。我通常只是在输出中 grep 查找“U”来检查未解析的符号,所以我认为这将是一个非常简单的脚本编写。
您可以为此使用 ldd 的递归版本吗?有人似乎写了一个可能有帮助的脚本......
对于任何像我在 15 年后所做的那样绊倒这个问题的人来说,@Todd Gamblin 帖子中的链接在 2019 年之后的某个时候就变暗了。我认为它可能对其他人有帮助,因为可以在互联网档案馆的 Wayback Machine 中找到它: https://web.archive.org/web/20190303004232/http://www.lysium.de/blog/index.php?/archives/35-Recursive-ldd.html
参考该脚本对我在 2024 年遇到几乎相同的问题很有帮助。