我正在使用用g ++编译的遗留C ++代码。有问题的文件是使用库编译的。 我的目标是确定每个文件中特定库中函数或宏的每次使用。(在我的情况下,OpenSSL是有问题的库,我会在整个过程中引用它但是,我认为我的问题通常适用于我编译的任何C库。)
如果OpenSSL是使用命名空间的C ++库,我可以想象这会更容易 - 我可以简单地在命名空间上查找OpenSSL函数。然而,由于它是一个C库,未修饰的OpenSSL函数和宏被分散在一些源文件中,我无法通过扫描源来判断哪些函数来自OpenSSL,哪些是其他本地函数或函数来自其他库。
通过Stack Overflow,我在Windows环境中看到了类似的问题,但我没有看到Linux环境的任何答案。扩展我的搜索,我看到nm
和objdump
的引用,但如果可以从目标文件中获取我正在寻找的这些工具的详细信息,我无法找出正确的参数使用。
提前感谢您的帮助!
答案 0 :(得分:1)
根据@firebrush的建议,我发表评论作为回答(也许是后人)。
为了查看库函数的使用位置您可以从链接中删除库,并查看.o
个文件缺少引用。
答案 1 :(得分:1)
我不认为有一个简单快速的解决方案,你必须为此做一些工作。 您的软件可以通过三种方式与openssl链接。
在所有情况下,最佳解决方案是从其位置删除头文件和openssl库并重新编译代码。 如果您无法访问代码,则必须使用nm或objdump从可执行文件中获取符号,并将它们与openssl库中的符号交叉引用。如果您使用dlopen链接库,这将不起作用。 另一种选择是获取openssl库并在启用跟踪的情况下重新编译它,并使用新库执行代码。
nm工具用于列出对象中的所有符号,无论它是库还是可执行文件。您可以创建一个bash脚本,该脚本在openssl库和可执行文件上交叉引用调用nm的输出。调用它的方法是nm objname。第三列是带符号的列。
objdump是一个更精确的工具,您可以使用它来列出您的未定义的所有符号。您可以使用它来列出可执行文件的标头( objdump -h objname ),这通常会列出您的可执行文件在运行时需要运行的所有库。如果此处列出了openssl,那么这意味着您将使用运行时链接器动态链接它。您可以将 objdump -R 与openssl一起使用来获取openssl接口中的符号。您可以使用可执行文件 objdump -r 时列出的符号交叉引用它
答案 2 :(得分:0)
我的同事能够使用nm获取此信息。这是我们遵循的程序:
正如上面的riodoro1所建议的那样,代码使用的库中的对象列表可以通过链接而不是库来获得(例如,在我的情况下没有-lcrypto
)。或者,这可以使用nm
在所有相关对象上运行nm
:
find . -name '*.o' -exec nm {} \; > nm.txt
查找由对象和条带符号引用的未定义符号:
grep '^ *U' nm.txt > nm2.txt
删除C ++符号(错误的名称以_Z开头),统一剩余的符号:
grep -v ' _Z' nm2.txt | sort | uniq > nm3.txt
手动修改nm3.txt
,删除不属于openssl的符号,写入nm4.txt
。
正常构建cc文件,将输出捕获到日志文件。隔离显示编译Lotus源文件的命令的行。在输出中搜索并替换以生成用于调用预处理器的命令。变化:
运行修改后的命令以生成预处理器输出。
预处理器输出包含所有包含的全文 头文件,后跟预处理的C代码。标题是 长而无趣,所以将它们从输出中剥离出来。我们会得到的 只是带有扩展宏的C代码。
bash -c 'for f in `find . -name "*.i"`; do cat "${f}" | perl cat-preproc-without-headers.pl > "${f}"cc; done'
这是cat-preproc-without-headers.pl的内容:
#!/usr/bin/perl
# Write lines to stdout if cat != 0
$cat = 0;
while(<>) {
if(/^# [1-9]\d* .*\.cc/) {
$cat = 1;
} elsif(/^# [0-9]/) {
$cat = 0;
} elsif($cat) {
print;
}
}
使用符号列表和扩展宏,您现在拥有库中的所有符号以及源代码中使用它们的位置。