如何在C ++文件中查找特定库使用的函数

时间:2017-05-31 14:56:53

标签: c++ g++

我正在使用用g ++编译的遗留C ++代码。有问题的文件是使用库编译的。 我的目标是确定每个文件中特定库中函数或宏的每次使用。(在我的情况下,OpenSSL是有问题的库,我会在整个过程中引用它但是,我认为我的问题通常适用于我编译的任何C库。)

如果OpenSSL是使用命名空间的C ++库,我可以想象这会更容易 - 我可以简单地在命名空间上查找OpenSSL函数。然而,由于它是一个C库,未修饰的OpenSSL函数和宏被分散在一些源文件中,我无法通过扫描源来判断哪些函数来自OpenSSL,哪些是其他本地函数或函数来自其他库。

通过Stack Overflow,我在Windows环境中看到了类似的问题,但我没有看到Linux环境的任何答案。扩展我的搜索,我看到nmobjdump的引用,但如果可以从目标文件中获取我正在寻找的这些工具的详细信息,我无法找出正确的参数使用。

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

根据@firebrush的建议,我发表评论作为回答(也许是后人)。

为了查看库函数的使用位置您可以从链接中删除库,并查看.o个文件缺少引用。

答案 1 :(得分:1)

我不认为有一个简单快速的解决方案,你必须为此做一些工作。 您的软件可以通过三种方式与openssl链接。

  1. 静态链接。
  2. 与运行时链接程序的动态链接
  3. 手动链接dlopen。
  4. 在所有情况下,最佳解决方案是从其位置删除头文件和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

如下所述获得
  1. 在所有相关对象上运行nm

    find . -name '*.o' -exec nm {} \; > nm.txt
    
  2. 查找由对象和条带符号引用的未定义符号:

    grep '^ *U' nm.txt > nm2.txt
    
  3. 删除C ++符号(错误的名称以_Z开头),统一剩余的符号:

    grep -v ' _Z' nm2.txt | sort | uniq > nm3.txt
    
  4. 手动修改nm3.txt,删除不属于openssl的符号,写入nm4.txt

  5. 使用预处理器扩展宏

    1. 正常构建cc文件,将输出捕获到日志文件。隔离显示编译Lotus源文件的命令的行。在输出中搜索并替换以生成用于调用预处理器的命令。变化:

      • -o ... / file.o => -o ... / file.i
      • ' - c'=> '-E'
    2. 运行修改后的命令以生成预处理器输出。

    3. 预处理器输出包含所有包含的全文 头文件,后跟预处理的C代码。标题是 长而无趣,所以将它们从输出中剥离出来。我们会得到的 只是带有扩展宏的C代码。

      bash -c 'for f in `find . -name "*.i"`; do cat "${f}" | perl cat-preproc-without-headers.pl > "${f}"cc; done'
      
    4. 这是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;
          }
      }
      

      结论

      使用符号列表和扩展宏,您现在拥有库中的所有符号以及源代码中使用它们的位置。