【问题标题】:List internal references in gcc or clang object files列出 gcc 或 clang 目标文件中的内部引用
【发布时间】:2015-05-30 18:52:41
【问题描述】:

给定一个公开符号的目标文件,我如何确定该符号是否也在内部使用?

我的目标是死函数检测。我已经有能力(通过readelf)查找它是否从另一个目标文件中使用,但是当它仅在内部使用时会失败。

如果重要的话,我正在使用 C++

【问题讨论】:

  • 内联和模板可能会让这变得困难......
  • 模板大多不是问题 b/c 它们通常仅在使用时实例化(例外是显式专业化),因此您只能在我的情况下看到它们> 寻找。考虑到一些调试器能够报告内联函数,尽管没有实际的堆栈帧,内联也是可以解决的。
  • "死函数检测"——为了警告?还是省略? LTO 不能有效地做到后者吗?
  • 用于检测,送至删除源代码。

标签: gcc clang object-code


【解决方案1】:

这实际上取决于您的编译器如何处理编译单元内调用,但有一些建议。

首先,如果您正在优化,编译器可能内联您的函数,即使它们没有标记为inline。实际上,如果函数用always_inline 属性标记,它会努力这样做。因此,没有证据表明函数 f 调用了函数 g,即使它确实这样做了。请注意,如果 g 本身是一个外部可访问的函数,编译器可能会生成两次(或更多次)其代码,首先以自己的名称用于外部调用,然后内联到 f(和其他调用函数)。

所以,避免优化并以某种方式抑制always_inline。您甚至可以显式指定 -fno-inline 以防止内联。

其次,您的目标架构可能具有相关的调用和分支指令。如果您的 fg 被放置在它们共同的代码段中,编译器可能会利用这一点。它是非内联函数的默认值。在这种情况下,编译器在编译时就知道调用位置与被调用者开头之间的偏移量,并可以生成相对调用或跳转指令;无需进一步搬迁。一些编译器可能会发出“无操作”重定位,但有些不会。不重定位表示不引用该符号。

所以,使用-ffunction-sections(对于数据-fdata-sections)。然后将每个函数放入其自己的部分,编译器别无选择,只能生成重定位以供链接器修复(从而使被调用者的符号被引用)。

请注意,如果您使用-ffunction-sections,然后在调用ld 时指定--gc-sections,编译器将丢弃所有未引用的部分。如果您随后添加-M,您将获得生成的模块图。废弃的功能不会显示在地图中。

附带说明,请记住,在某些情况下,静态分析无法检测到函数永远无法被调用。例如,在编写良好的 C++ 程序中,__cxa_pure_virtual 永远不会被调用,但在所有抽象类的虚函数表中都会引用它。此外,即使在整个程序中没有对该虚函数的单个调用,普通虚函数的覆盖也将通过虚函数表引用并链接。符号分析无法检测到这些情况。

【讨论】:

  • 我愿意并且能够使用所需的任何标志进行构建。如果删除它们使构建失败,我也愿意有一些误报。
  • 如果“误报”是指一个已使用但未被识别的函数,那么在 C++ 中没有可靠的方法将其从源代码中删除,这样构建就会失败。假设您有一个void f(int) 和一个void f(long)。如果您错误地将void f(long) 标识为未使用并将其删除,那么编译器很可能不会抱怨,因为在所有调用它的地方,重载决议现在都会默默地选择另一个重载。
  • 另一方面,由于C没有函数重载和模板,这样做是相当安全的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
相关资源
最近更新 更多