检查静态库是否不包含未定义的符号,但来自 libc 和 stdlib 的符号除外

Checking that a static library does not contain undefined symbols exept ones from libc and stdlib

提问人:many-sigsegv 提问时间:6/22/2023 最后编辑:many-sigsegv 更新时间:7/3/2023 访问量:160

问:

我构建了一个 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 提供的每个函数的可执行文件链接似乎是唯一的解决方案。

静态库 libc libc++ 未定义符号

评论


答:

0赞 Employed Russian 6/25/2023 #1

一个可能的解决方案是将测试可执行文件与 static_lib.a 链接,并依靠链接器来查找未定义的引用,但此类可执行文件需要调用 API 提供的每个函数,并在添加/删除函数时手动更新。

另一种可能的解决方案是使用 (其中是您存档到 ) 中的所有对象文件,然后与 链接。如果链接成功,则没有未解析的符号。ld -r ${OBJS} -o lib.o${OBJS}static_lib.amain.olib.o

问题是 libc.so 实际上是一个文本文件

它实际上是一个链接器脚本。但是它确切地告诉你它将使用哪个,所以你可以扫描这些。libc.so.6libc_nonshared.a

0赞 many-sigsegv 7/3/2023 #2

为了避免 nm 无法读取链接器脚本的问题,可以直接使用链接器。

新步骤:

仍然用于获取 libc 和 stdlib(和 pthread)路径,并将库中未定义符号的列表转储到“未定义”文件中。gcc [cflags] --print-file-namenm --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,}