提问人:many-sigsegv 提问时间:6/22/2023 最后编辑:many-sigsegv 更新时间:7/3/2023 访问量:160
检查静态库是否不包含未定义的符号,但来自 libc 和 stdlib 的符号除外
Checking that a static library does not contain undefined symbols exept ones from libc and stdlib
问:
我构建了一个 c++ 软件模块,该模块以包含 API 的头文件 (.h) 和带有实现的静态库 (.a) 的形式提供。
该模块仅依赖于标准库,因此我想检查 static_lib.a 中所有未定义的符号是否实际存在于 libc 和 stdlib 中,否则这意味着缺少函数实现。
该模块是在 x86_64 Linux 计算机上为 aarch64 交叉构建的。
一个可能的解决方案是将测试可执行文件与 static_lib.a 链接,并依靠链接器来查找未定义的引用,但此类可执行文件需要调用 API 提供的每个函数,并在添加/删除函数时手动更新。
到目前为止,我得到的最好的解决方案是:
- 获取 libc.so 和 libstdc++.so 路径
gcc [cflags] --print-file-name=libc.so
gcc [cflags] --print-file-name=libstdc++.so
- 获取 libc 和 stdlib 提供的符号列表
nm --format=posix --dynamic $LIBC_PATH $LIBSTD_PATH | awk '{print $1}' | grep -v ':$' > stdsyms
- 使用 获取库中未定义符号的列表
nm --format=posix --undefined-only static_lib.a | awk '{print $1}' | grep -v ':$' > undefined
- 检查 stdsyms 中是否存在 undefined 中的所有符号
while read symbol; do grep -q "^$symbol$" stdsyms || echo $symbol >> missing; done < undefined
if [ -s missing ]; then echo "missing symbols:"; cat missing; false; fi
问题是 libc.so 实际上是一个文本文件
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf64-littleaarch64)
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-aarch64.so.1 ) )
所以 nm 无法解析它。我想知道解析此文件以提取 /lib/libc.so.6 并从 gcc cflags 中提取 --sysroot 参数以构建实际的 libc 共享库路径,但这似乎很脆弱......
我试过了,但没有结果。gcc [cflags] --print-file-name=libc.a
有没有人有更好的主意来检查实现中是否缺少函数?通过使用可靠的方法从 libc 和 stdlib 导出符号,或者使用其他方法。
编辑以下受雇的俄语答案:
实际上,库已经使用了部分链接(使用标志)。-r -nostlib
然后将 main.o 与 lib.o 链接 如果链接成功,则没有未解析的符号。
这需要用于创建 main.o 的 main.c 调用库 API 的每个函数,我认为没有简单的方法可以自动化这一点。
它实际上是一个链接器脚本。但它会确切地告诉你它将使用哪个 libc.so.6 和 libc_nonshared.a,所以你可以扫描它们。
我可能最终会这样做,我希望有一个解决方案来避免手动解析此文件(也许在特殊模式下调用链接器?我会做一些测试。
溶液:
有关避免 nm 问题的解决方案,请参阅 https://stackoverflow.com/a/76605971/12251948。请注意,这只允许获取“未定义”的符号,而不是“缺失”的符号,对于这些符号,与调用 API 提供的每个函数的可执行文件链接似乎是唯一的解决方案。
答:
一个可能的解决方案是将测试可执行文件与 static_lib.a 链接,并依靠链接器来查找未定义的引用,但此类可执行文件需要调用 API 提供的每个函数,并在添加/删除函数时手动更新。
另一种可能的解决方案是使用 (其中是您存档到 ) 中的所有对象文件,然后与 链接。如果链接成功,则没有未解析的符号。ld -r ${OBJS} -o lib.o
${OBJS}
static_lib.a
main.o
lib.o
问题是 libc.so 实际上是一个文本文件
它实际上是一个链接器脚本。但是它确切地告诉你它将使用哪个,所以你可以扫描这些。libc.so.6
libc_nonshared.a
为了避免 nm 无法读取链接器脚本的问题,可以直接使用链接器。
新步骤:
仍然用于获取 libc 和 stdlib(和 pthread)路径,并将库中未定义符号的列表转储到“未定义”文件中。gcc [cflags] --print-file-name
nm --format=posix --undefined-only static_lib.a
然后调用链接器,路径为 libc、stdlib 和 pthread lib,并要求解析来自“undefined”的符号
readarray -t symbols < undefined && gcc [ldflags] -Wl,--no-as-needed $LIBC_PATH $LIBSTD_PATH $LIBPTHREAD_PATH ${symbols[@]/#/ -Wl,--require-defined -Wl,} -Wl,--ignore-unresolved-symbol -Wl,main
并允许为库中每个未定义的符号的链接器生成 --require-defined 参数。
如果链接失败,这意味着存在不属于 libc、stdlib 或 pthread 的未定义符号。readarray -t symbols
${symbols[@]/#/ -Wl,--require-defined -Wl,}
评论